Subversion Repositories Mobile Apps.GyroMouse

Rev

Blame | Last modification | View Log | Download | RSS feed

  1. //
  2. //  GCDAsyncSocket.m
  3. //  
  4. //  This class is in the public domain.
  5. //  Originally created by Robbie Hanson in Q4 2010.
  6. //  Updated and maintained by Deusty LLC and the Apple development community.
  7. //
  8. //  https://github.com/robbiehanson/CocoaAsyncSocket
  9. //
  10.  
  11. #import "GCDAsyncSocket.h"
  12.  
  13. #if TARGET_OS_IPHONE
  14. #import <CFNetwork/CFNetwork.h>
  15. #endif
  16.  
  17. #import <TargetConditionals.h>
  18. #import <arpa/inet.h>
  19. #import <fcntl.h>
  20. #import <ifaddrs.h>
  21. #import <netdb.h>
  22. #import <netinet/in.h>
  23. #import <net/if.h>
  24. #import <sys/socket.h>
  25. #import <sys/types.h>
  26. #import <sys/ioctl.h>
  27. #import <sys/poll.h>
  28. #import <sys/uio.h>
  29. #import <sys/un.h>
  30. #import <unistd.h>
  31.  
  32. #if ! __has_feature(objc_arc)
  33. #warning This file must be compiled with ARC. Use -fobjc-arc flag (or convert project to ARC).
  34. // For more information see: https://github.com/robbiehanson/CocoaAsyncSocket/wiki/ARC
  35. #endif
  36.  
  37.  
  38. #ifndef GCDAsyncSocketLoggingEnabled
  39. #define GCDAsyncSocketLoggingEnabled 0
  40. #endif
  41.  
  42. #if GCDAsyncSocketLoggingEnabled
  43.  
  44. // Logging Enabled - See log level below
  45.  
  46. // Logging uses the CocoaLumberjack framework (which is also GCD based).
  47. // https://github.com/robbiehanson/CocoaLumberjack
  48. //
  49. // It allows us to do a lot of logging without significantly slowing down the code.
  50. #import "DDLog.h"
  51.  
  52. #define LogAsync   YES
  53. #define LogContext GCDAsyncSocketLoggingContext
  54.  
  55. #define LogObjc(flg, frmt, ...) LOG_OBJC_MAYBE(LogAsync, logLevel, flg, LogContext, frmt, ##__VA_ARGS__)
  56. #define LogC(flg, frmt, ...)    LOG_C_MAYBE(LogAsync, logLevel, flg, LogContext, frmt, ##__VA_ARGS__)
  57.  
  58. #define LogError(frmt, ...)     LogObjc(LOG_FLAG_ERROR,   (@"%@: " frmt), THIS_FILE, ##__VA_ARGS__)
  59. #define LogWarn(frmt, ...)      LogObjc(LOG_FLAG_WARN,    (@"%@: " frmt), THIS_FILE, ##__VA_ARGS__)
  60. #define LogInfo(frmt, ...)      LogObjc(LOG_FLAG_INFO,    (@"%@: " frmt), THIS_FILE, ##__VA_ARGS__)
  61. #define LogVerbose(frmt, ...)   LogObjc(LOG_FLAG_VERBOSE, (@"%@: " frmt), THIS_FILE, ##__VA_ARGS__)
  62.  
  63. #define LogCError(frmt, ...)    LogC(LOG_FLAG_ERROR,   (@"%@: " frmt), THIS_FILE, ##__VA_ARGS__)
  64. #define LogCWarn(frmt, ...)     LogC(LOG_FLAG_WARN,    (@"%@: " frmt), THIS_FILE, ##__VA_ARGS__)
  65. #define LogCInfo(frmt, ...)     LogC(LOG_FLAG_INFO,    (@"%@: " frmt), THIS_FILE, ##__VA_ARGS__)
  66. #define LogCVerbose(frmt, ...)  LogC(LOG_FLAG_VERBOSE, (@"%@: " frmt), THIS_FILE, ##__VA_ARGS__)
  67.  
  68. #define LogTrace()              LogObjc(LOG_FLAG_VERBOSE, @"%@: %@", THIS_FILE, THIS_METHOD)
  69. #define LogCTrace()             LogC(LOG_FLAG_VERBOSE, @"%@: %s", THIS_FILE, __FUNCTION__)
  70.  
  71. #ifndef GCDAsyncSocketLogLevel
  72. #define GCDAsyncSocketLogLevel LOG_LEVEL_VERBOSE
  73. #endif
  74.  
  75. // Log levels : off, error, warn, info, verbose
  76. static const int logLevel = GCDAsyncSocketLogLevel;
  77.  
  78. #else
  79.  
  80. // Logging Disabled
  81.  
  82. #define LogError(frmt, ...)     {}
  83. #define LogWarn(frmt, ...)      {}
  84. #define LogInfo(frmt, ...)      {}
  85. #define LogVerbose(frmt, ...)   {}
  86.  
  87. #define LogCError(frmt, ...)    {}
  88. #define LogCWarn(frmt, ...)     {}
  89. #define LogCInfo(frmt, ...)     {}
  90. #define LogCVerbose(frmt, ...)  {}
  91.  
  92. #define LogTrace()              {}
  93. #define LogCTrace(frmt, ...)    {}
  94.  
  95. #endif
  96.  
  97. /**
  98.  * Seeing a return statements within an inner block
  99.  * can sometimes be mistaken for a return point of the enclosing method.
  100.  * This makes inline blocks a bit easier to read.
  101. **/
  102. #define return_from_block  return
  103.  
  104. /**
  105.  * A socket file descriptor is really just an integer.
  106.  * It represents the index of the socket within the kernel.
  107.  * This makes invalid file descriptor comparisons easier to read.
  108. **/
  109. #define SOCKET_NULL -1
  110.  
  111.  
  112. NSString *const GCDAsyncSocketException = @"GCDAsyncSocketException";
  113. NSString *const GCDAsyncSocketErrorDomain = @"GCDAsyncSocketErrorDomain";
  114.  
  115. NSString *const GCDAsyncSocketQueueName = @"GCDAsyncSocket";
  116. NSString *const GCDAsyncSocketThreadName = @"GCDAsyncSocket-CFStream";
  117.  
  118. NSString *const GCDAsyncSocketManuallyEvaluateTrust = @"GCDAsyncSocketManuallyEvaluateTrust";
  119. #if TARGET_OS_IPHONE
  120. NSString *const GCDAsyncSocketUseCFStreamForTLS = @"GCDAsyncSocketUseCFStreamForTLS";
  121. #endif
  122. NSString *const GCDAsyncSocketSSLPeerID = @"GCDAsyncSocketSSLPeerID";
  123. NSString *const GCDAsyncSocketSSLProtocolVersionMin = @"GCDAsyncSocketSSLProtocolVersionMin";
  124. NSString *const GCDAsyncSocketSSLProtocolVersionMax = @"GCDAsyncSocketSSLProtocolVersionMax";
  125. NSString *const GCDAsyncSocketSSLSessionOptionFalseStart = @"GCDAsyncSocketSSLSessionOptionFalseStart";
  126. NSString *const GCDAsyncSocketSSLSessionOptionSendOneByteRecord = @"GCDAsyncSocketSSLSessionOptionSendOneByteRecord";
  127. NSString *const GCDAsyncSocketSSLCipherSuites = @"GCDAsyncSocketSSLCipherSuites";
  128. NSString *const GCDAsyncSocketSSLALPN = @"GCDAsyncSocketSSLALPN";
  129. #if !TARGET_OS_IPHONE
  130. NSString *const GCDAsyncSocketSSLDiffieHellmanParameters = @"GCDAsyncSocketSSLDiffieHellmanParameters";
  131. #endif
  132.  
  133. enum GCDAsyncSocketFlags
  134. {
  135.         kSocketStarted                 = 1 <<  0,  // If set, socket has been started (accepting/connecting)
  136.         kConnected                     = 1 <<  1,  // If set, the socket is connected
  137.         kForbidReadsWrites             = 1 <<  2,  // If set, no new reads or writes are allowed
  138.         kReadsPaused                   = 1 <<  3,  // If set, reads are paused due to possible timeout
  139.         kWritesPaused                  = 1 <<  4,  // If set, writes are paused due to possible timeout
  140.         kDisconnectAfterReads          = 1 <<  5,  // If set, disconnect after no more reads are queued
  141.         kDisconnectAfterWrites         = 1 <<  6,  // If set, disconnect after no more writes are queued
  142.         kSocketCanAcceptBytes          = 1 <<  7,  // If set, we know socket can accept bytes. If unset, it's unknown.
  143.         kReadSourceSuspended           = 1 <<  8,  // If set, the read source is suspended
  144.         kWriteSourceSuspended          = 1 <<  9,  // If set, the write source is suspended
  145.         kQueuedTLS                     = 1 << 10,  // If set, we've queued an upgrade to TLS
  146.         kStartingReadTLS               = 1 << 11,  // If set, we're waiting for TLS negotiation to complete
  147.         kStartingWriteTLS              = 1 << 12,  // If set, we're waiting for TLS negotiation to complete
  148.         kSocketSecure                  = 1 << 13,  // If set, socket is using secure communication via SSL/TLS
  149.         kSocketHasReadEOF              = 1 << 14,  // If set, we have read EOF from socket
  150.         kReadStreamClosed              = 1 << 15,  // If set, we've read EOF plus prebuffer has been drained
  151.         kDealloc                       = 1 << 16,  // If set, the socket is being deallocated
  152. #if TARGET_OS_IPHONE
  153.         kAddedStreamsToRunLoop         = 1 << 17,  // If set, CFStreams have been added to listener thread
  154.         kUsingCFStreamForTLS           = 1 << 18,  // If set, we're forced to use CFStream instead of SecureTransport
  155.         kSecureSocketHasBytesAvailable = 1 << 19,  // If set, CFReadStream has notified us of bytes available
  156. #endif
  157. };
  158.  
  159. enum GCDAsyncSocketConfig
  160. {
  161.         kIPv4Disabled              = 1 << 0,  // If set, IPv4 is disabled
  162.         kIPv6Disabled              = 1 << 1,  // If set, IPv6 is disabled
  163.         kPreferIPv6                = 1 << 2,  // If set, IPv6 is preferred over IPv4
  164.         kAllowHalfDuplexConnection = 1 << 3,  // If set, the socket will stay open even if the read stream closes
  165. };
  166.  
  167. #if TARGET_OS_IPHONE
  168.   static NSThread *cfstreamThread;  // Used for CFStreams
  169.  
  170.  
  171.   static uint64_t cfstreamThreadRetainCount;   // setup & teardown
  172.   static dispatch_queue_t cfstreamThreadSetupQueue; // setup & teardown
  173. #endif
  174.  
  175. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  176. #pragma mark -
  177. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  178.  
  179. /**
  180.  * A PreBuffer is used when there is more data available on the socket
  181.  * than is being requested by current read request.
  182.  * In this case we slurp up all data from the socket (to minimize sys calls),
  183.  * and store additional yet unread data in a "prebuffer".
  184.  *
  185.  * The prebuffer is entirely drained before we read from the socket again.
  186.  * In other words, a large chunk of data is written is written to the prebuffer.
  187.  * The prebuffer is then drained via a series of one or more reads (for subsequent read request(s)).
  188.  *
  189.  * A ring buffer was once used for this purpose.
  190.  * But a ring buffer takes up twice as much memory as needed (double the size for mirroring).
  191.  * In fact, it generally takes up more than twice the needed size as everything has to be rounded up to vm_page_size.
  192.  * And since the prebuffer is always completely drained after being written to, a full ring buffer isn't needed.
  193.  *
  194.  * The current design is very simple and straight-forward, while also keeping memory requirements lower.
  195. **/
  196.  
  197. @interface GCDAsyncSocketPreBuffer : NSObject
  198. {
  199.         uint8_t *preBuffer;
  200.         size_t preBufferSize;
  201.        
  202.         uint8_t *readPointer;
  203.         uint8_t *writePointer;
  204. }
  205.  
  206. - (instancetype)initWithCapacity:(size_t)numBytes NS_DESIGNATED_INITIALIZER;
  207.  
  208. - (void)ensureCapacityForWrite:(size_t)numBytes;
  209.  
  210. - (size_t)availableBytes;
  211. - (uint8_t *)readBuffer;
  212.  
  213. - (void)getReadBuffer:(uint8_t **)bufferPtr availableBytes:(size_t *)availableBytesPtr;
  214.  
  215. - (size_t)availableSpace;
  216. - (uint8_t *)writeBuffer;
  217.  
  218. - (void)getWriteBuffer:(uint8_t **)bufferPtr availableSpace:(size_t *)availableSpacePtr;
  219.  
  220. - (void)didRead:(size_t)bytesRead;
  221. - (void)didWrite:(size_t)bytesWritten;
  222.  
  223. - (void)reset;
  224.  
  225. @end
  226.  
  227. @implementation GCDAsyncSocketPreBuffer
  228.  
  229. // Cover the superclass' designated initializer
  230. - (instancetype)init NS_UNAVAILABLE
  231. {
  232.         NSAssert(0, @"Use the designated initializer");
  233.         return nil;
  234. }
  235.  
  236. - (instancetype)initWithCapacity:(size_t)numBytes
  237. {
  238.         if ((self = [super init]))
  239.         {
  240.                 preBufferSize = numBytes;
  241.                 preBuffer = malloc(preBufferSize);
  242.                
  243.                 readPointer = preBuffer;
  244.                 writePointer = preBuffer;
  245.         }
  246.         return self;
  247. }
  248.  
  249. - (void)dealloc
  250. {
  251.         if (preBuffer)
  252.                 free(preBuffer);
  253. }
  254.  
  255. - (void)ensureCapacityForWrite:(size_t)numBytes
  256. {
  257.         size_t availableSpace = [self availableSpace];
  258.        
  259.         if (numBytes > availableSpace)
  260.         {
  261.                 size_t additionalBytes = numBytes - availableSpace;
  262.                
  263.                 size_t newPreBufferSize = preBufferSize + additionalBytes;
  264.                 uint8_t *newPreBuffer = realloc(preBuffer, newPreBufferSize);
  265.                
  266.                 size_t readPointerOffset = readPointer - preBuffer;
  267.                 size_t writePointerOffset = writePointer - preBuffer;
  268.                
  269.                 preBuffer = newPreBuffer;
  270.                 preBufferSize = newPreBufferSize;
  271.                
  272.                 readPointer = preBuffer + readPointerOffset;
  273.                 writePointer = preBuffer + writePointerOffset;
  274.         }
  275. }
  276.  
  277. - (size_t)availableBytes
  278. {
  279.         return writePointer - readPointer;
  280. }
  281.  
  282. - (uint8_t *)readBuffer
  283. {
  284.         return readPointer;
  285. }
  286.  
  287. - (void)getReadBuffer:(uint8_t **)bufferPtr availableBytes:(size_t *)availableBytesPtr
  288. {
  289.         if (bufferPtr) *bufferPtr = readPointer;
  290.         if (availableBytesPtr) *availableBytesPtr = [self availableBytes];
  291. }
  292.  
  293. - (void)didRead:(size_t)bytesRead
  294. {
  295.         readPointer += bytesRead;
  296.        
  297.         if (readPointer == writePointer)
  298.         {
  299.                 // The prebuffer has been drained. Reset pointers.
  300.                 readPointer  = preBuffer;
  301.                 writePointer = preBuffer;
  302.         }
  303. }
  304.  
  305. - (size_t)availableSpace
  306. {
  307.         return preBufferSize - (writePointer - preBuffer);
  308. }
  309.  
  310. - (uint8_t *)writeBuffer
  311. {
  312.         return writePointer;
  313. }
  314.  
  315. - (void)getWriteBuffer:(uint8_t **)bufferPtr availableSpace:(size_t *)availableSpacePtr
  316. {
  317.         if (bufferPtr) *bufferPtr = writePointer;
  318.         if (availableSpacePtr) *availableSpacePtr = [self availableSpace];
  319. }
  320.  
  321. - (void)didWrite:(size_t)bytesWritten
  322. {
  323.         writePointer += bytesWritten;
  324. }
  325.  
  326. - (void)reset
  327. {
  328.         readPointer  = preBuffer;
  329.         writePointer = preBuffer;
  330. }
  331.  
  332. @end
  333.  
  334. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  335. #pragma mark -
  336. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  337.  
  338. /**
  339.  * The GCDAsyncReadPacket encompasses the instructions for any given read.
  340.  * The content of a read packet allows the code to determine if we're:
  341.  *  - reading to a certain length
  342.  *  - reading to a certain separator
  343.  *  - or simply reading the first chunk of available data
  344. **/
  345. @interface GCDAsyncReadPacket : NSObject
  346. {
  347.   @public
  348.         NSMutableData *buffer;
  349.         NSUInteger startOffset;
  350.         NSUInteger bytesDone;
  351.         NSUInteger maxLength;
  352.         NSTimeInterval timeout;
  353.         NSUInteger readLength;
  354.         NSData *term;
  355.         BOOL bufferOwner;
  356.         NSUInteger originalBufferLength;
  357.         long tag;
  358. }
  359. - (instancetype)initWithData:(NSMutableData *)d
  360.                  startOffset:(NSUInteger)s
  361.                    maxLength:(NSUInteger)m
  362.                      timeout:(NSTimeInterval)t
  363.                   readLength:(NSUInteger)l
  364.                   terminator:(NSData *)e
  365.                          tag:(long)i NS_DESIGNATED_INITIALIZER;
  366.  
  367. - (void)ensureCapacityForAdditionalDataOfLength:(NSUInteger)bytesToRead;
  368.  
  369. - (NSUInteger)optimalReadLengthWithDefault:(NSUInteger)defaultValue shouldPreBuffer:(BOOL *)shouldPreBufferPtr;
  370.  
  371. - (NSUInteger)readLengthForNonTermWithHint:(NSUInteger)bytesAvailable;
  372. - (NSUInteger)readLengthForTermWithHint:(NSUInteger)bytesAvailable shouldPreBuffer:(BOOL *)shouldPreBufferPtr;
  373. - (NSUInteger)readLengthForTermWithPreBuffer:(GCDAsyncSocketPreBuffer *)preBuffer found:(BOOL *)foundPtr;
  374.  
  375. - (NSInteger)searchForTermAfterPreBuffering:(ssize_t)numBytes;
  376.  
  377. @end
  378.  
  379. @implementation GCDAsyncReadPacket
  380.  
  381. // Cover the superclass' designated initializer
  382. - (instancetype)init NS_UNAVAILABLE
  383. {
  384.         NSAssert(0, @"Use the designated initializer");
  385.         return nil;
  386. }
  387.  
  388. - (instancetype)initWithData:(NSMutableData *)d
  389.                  startOffset:(NSUInteger)s
  390.                    maxLength:(NSUInteger)m
  391.                      timeout:(NSTimeInterval)t
  392.                   readLength:(NSUInteger)l
  393.                   terminator:(NSData *)e
  394.                          tag:(long)i
  395. {
  396.         if((self = [super init]))
  397.         {
  398.                 bytesDone = 0;
  399.                 maxLength = m;
  400.                 timeout = t;
  401.                 readLength = l;
  402.                 term = [e copy];
  403.                 tag = i;
  404.                
  405.                 if (d)
  406.                 {
  407.                         buffer = d;
  408.                         startOffset = s;
  409.                         bufferOwner = NO;
  410.                         originalBufferLength = [d length];
  411.                 }
  412.                 else
  413.                 {
  414.                         if (readLength > 0)
  415.                                 buffer = [[NSMutableData alloc] initWithLength:readLength];
  416.                         else
  417.                                 buffer = [[NSMutableData alloc] initWithLength:0];
  418.                        
  419.                         startOffset = 0;
  420.                         bufferOwner = YES;
  421.                         originalBufferLength = 0;
  422.                 }
  423.         }
  424.         return self;
  425. }
  426.  
  427. /**
  428.  * Increases the length of the buffer (if needed) to ensure a read of the given size will fit.
  429. **/
  430. - (void)ensureCapacityForAdditionalDataOfLength:(NSUInteger)bytesToRead
  431. {
  432.         NSUInteger buffSize = [buffer length];
  433.         NSUInteger buffUsed = startOffset + bytesDone;
  434.        
  435.         NSUInteger buffSpace = buffSize - buffUsed;
  436.        
  437.         if (bytesToRead > buffSpace)
  438.         {
  439.                 NSUInteger buffInc = bytesToRead - buffSpace;
  440.                
  441.                 [buffer increaseLengthBy:buffInc];
  442.         }
  443. }
  444.  
  445. /**
  446.  * This method is used when we do NOT know how much data is available to be read from the socket.
  447.  * This method returns the default value unless it exceeds the specified readLength or maxLength.
  448.  *
  449.  * Furthermore, the shouldPreBuffer decision is based upon the packet type,
  450.  * and whether the returned value would fit in the current buffer without requiring a resize of the buffer.
  451. **/
  452. - (NSUInteger)optimalReadLengthWithDefault:(NSUInteger)defaultValue shouldPreBuffer:(BOOL *)shouldPreBufferPtr
  453. {
  454.         NSUInteger result;
  455.        
  456.         if (readLength > 0)
  457.         {
  458.                 // Read a specific length of data
  459.                 result = readLength - bytesDone;
  460.                
  461.                 // There is no need to prebuffer since we know exactly how much data we need to read.
  462.                 // Even if the buffer isn't currently big enough to fit this amount of data,
  463.                 // it would have to be resized eventually anyway.
  464.                
  465.                 if (shouldPreBufferPtr)
  466.                         *shouldPreBufferPtr = NO;
  467.         }
  468.         else
  469.         {
  470.                 // Either reading until we find a specified terminator,
  471.                 // or we're simply reading all available data.
  472.                 //
  473.                 // In other words, one of:
  474.                 //
  475.                 // - readDataToData packet
  476.                 // - readDataWithTimeout packet
  477.                
  478.                 if (maxLength > 0)
  479.                         result =  MIN(defaultValue, (maxLength - bytesDone));
  480.                 else
  481.                         result = defaultValue;
  482.                
  483.                 // Since we don't know the size of the read in advance,
  484.                 // the shouldPreBuffer decision is based upon whether the returned value would fit
  485.                 // in the current buffer without requiring a resize of the buffer.
  486.                 //
  487.                 // This is because, in all likelyhood, the amount read from the socket will be less than the default value.
  488.                 // Thus we should avoid over-allocating the read buffer when we can simply use the pre-buffer instead.
  489.                
  490.                 if (shouldPreBufferPtr)
  491.                 {
  492.                         NSUInteger buffSize = [buffer length];
  493.                         NSUInteger buffUsed = startOffset + bytesDone;
  494.                        
  495.                         NSUInteger buffSpace = buffSize - buffUsed;
  496.                        
  497.                         if (buffSpace >= result)
  498.                                 *shouldPreBufferPtr = NO;
  499.                         else
  500.                                 *shouldPreBufferPtr = YES;
  501.                 }
  502.         }
  503.        
  504.         return result;
  505. }
  506.  
  507. /**
  508.  * For read packets without a set terminator, returns the amount of data
  509.  * that can be read without exceeding the readLength or maxLength.
  510.  *
  511.  * The given parameter indicates the number of bytes estimated to be available on the socket,
  512.  * which is taken into consideration during the calculation.
  513.  *
  514.  * The given hint MUST be greater than zero.
  515. **/
  516. - (NSUInteger)readLengthForNonTermWithHint:(NSUInteger)bytesAvailable
  517. {
  518.         NSAssert(term == nil, @"This method does not apply to term reads");
  519.         NSAssert(bytesAvailable > 0, @"Invalid parameter: bytesAvailable");
  520.        
  521.         if (readLength > 0)
  522.         {
  523.                 // Read a specific length of data
  524.                
  525.                 return MIN(bytesAvailable, (readLength - bytesDone));
  526.                
  527.                 // No need to avoid resizing the buffer.
  528.                 // If the user provided their own buffer,
  529.                 // and told us to read a certain length of data that exceeds the size of the buffer,
  530.                 // then it is clear that our code will resize the buffer during the read operation.
  531.                 //
  532.                 // This method does not actually do any resizing.
  533.                 // The resizing will happen elsewhere if needed.
  534.         }
  535.         else
  536.         {
  537.                 // Read all available data
  538.                
  539.                 NSUInteger result = bytesAvailable;
  540.                
  541.                 if (maxLength > 0)
  542.                 {
  543.                         result = MIN(result, (maxLength - bytesDone));
  544.                 }
  545.                
  546.                 // No need to avoid resizing the buffer.
  547.                 // If the user provided their own buffer,
  548.                 // and told us to read all available data without giving us a maxLength,
  549.                 // then it is clear that our code might resize the buffer during the read operation.
  550.                 //
  551.                 // This method does not actually do any resizing.
  552.                 // The resizing will happen elsewhere if needed.
  553.                
  554.                 return result;
  555.         }
  556. }
  557.  
  558. /**
  559.  * For read packets with a set terminator, returns the amount of data
  560.  * that can be read without exceeding the maxLength.
  561.  *
  562.  * The given parameter indicates the number of bytes estimated to be available on the socket,
  563.  * which is taken into consideration during the calculation.
  564.  *
  565.  * To optimize memory allocations, mem copies, and mem moves
  566.  * the shouldPreBuffer boolean value will indicate if the data should be read into a prebuffer first,
  567.  * or if the data can be read directly into the read packet's buffer.
  568. **/
  569. - (NSUInteger)readLengthForTermWithHint:(NSUInteger)bytesAvailable shouldPreBuffer:(BOOL *)shouldPreBufferPtr
  570. {
  571.         NSAssert(term != nil, @"This method does not apply to non-term reads");
  572.         NSAssert(bytesAvailable > 0, @"Invalid parameter: bytesAvailable");
  573.        
  574.        
  575.         NSUInteger result = bytesAvailable;
  576.        
  577.         if (maxLength > 0)
  578.         {
  579.                 result = MIN(result, (maxLength - bytesDone));
  580.         }
  581.        
  582.         // Should the data be read into the read packet's buffer, or into a pre-buffer first?
  583.         //
  584.         // One would imagine the preferred option is the faster one.
  585.         // So which one is faster?
  586.         //
  587.         // Reading directly into the packet's buffer requires:
  588.         // 1. Possibly resizing packet buffer (malloc/realloc)
  589.         // 2. Filling buffer (read)
  590.         // 3. Searching for term (memcmp)
  591.         // 4. Possibly copying overflow into prebuffer (malloc/realloc, memcpy)
  592.         //
  593.         // Reading into prebuffer first:
  594.         // 1. Possibly resizing prebuffer (malloc/realloc)
  595.         // 2. Filling buffer (read)
  596.         // 3. Searching for term (memcmp)
  597.         // 4. Copying underflow into packet buffer (malloc/realloc, memcpy)
  598.         // 5. Removing underflow from prebuffer (memmove)
  599.         //
  600.         // Comparing the performance of the two we can see that reading
  601.         // data into the prebuffer first is slower due to the extra memove.
  602.         //
  603.         // However:
  604.         // The implementation of NSMutableData is open source via core foundation's CFMutableData.
  605.         // Decreasing the length of a mutable data object doesn't cause a realloc.
  606.         // In other words, the capacity of a mutable data object can grow, but doesn't shrink.
  607.         //
  608.         // This means the prebuffer will rarely need a realloc.
  609.         // The packet buffer, on the other hand, may often need a realloc.
  610.         // This is especially true if we are the buffer owner.
  611.         // Furthermore, if we are constantly realloc'ing the packet buffer,
  612.         // and then moving the overflow into the prebuffer,
  613.         // then we're consistently over-allocating memory for each term read.
  614.         // And now we get into a bit of a tradeoff between speed and memory utilization.
  615.         //
  616.         // The end result is that the two perform very similarly.
  617.         // And we can answer the original question very simply by another means.
  618.         //
  619.         // If we can read all the data directly into the packet's buffer without resizing it first,
  620.         // then we do so. Otherwise we use the prebuffer.
  621.        
  622.         if (shouldPreBufferPtr)
  623.         {
  624.                 NSUInteger buffSize = [buffer length];
  625.                 NSUInteger buffUsed = startOffset + bytesDone;
  626.                
  627.                 if ((buffSize - buffUsed) >= result)
  628.                         *shouldPreBufferPtr = NO;
  629.                 else
  630.                         *shouldPreBufferPtr = YES;
  631.         }
  632.        
  633.         return result;
  634. }
  635.  
  636. /**
  637.  * For read packets with a set terminator,
  638.  * returns the amount of data that can be read from the given preBuffer,
  639.  * without going over a terminator or the maxLength.
  640.  *
  641.  * It is assumed the terminator has not already been read.
  642. **/
  643. - (NSUInteger)readLengthForTermWithPreBuffer:(GCDAsyncSocketPreBuffer *)preBuffer found:(BOOL *)foundPtr
  644. {
  645.         NSAssert(term != nil, @"This method does not apply to non-term reads");
  646.         NSAssert([preBuffer availableBytes] > 0, @"Invoked with empty pre buffer!");
  647.        
  648.         // We know that the terminator, as a whole, doesn't exist in our own buffer.
  649.         // But it is possible that a _portion_ of it exists in our buffer.
  650.         // So we're going to look for the terminator starting with a portion of our own buffer.
  651.         //
  652.         // Example:
  653.         //
  654.         // term length      = 3 bytes
  655.         // bytesDone        = 5 bytes
  656.         // preBuffer length = 5 bytes
  657.         //
  658.         // If we append the preBuffer to our buffer,
  659.         // it would look like this:
  660.         //
  661.         // ---------------------
  662.         // |B|B|B|B|B|P|P|P|P|P|
  663.         // ---------------------
  664.         //
  665.         // So we start our search here:
  666.         //
  667.         // ---------------------
  668.         // |B|B|B|B|B|P|P|P|P|P|
  669.         // -------^-^-^---------
  670.         //
  671.         // And move forwards...
  672.         //
  673.         // ---------------------
  674.         // |B|B|B|B|B|P|P|P|P|P|
  675.         // ---------^-^-^-------
  676.         //
  677.         // Until we find the terminator or reach the end.
  678.         //
  679.         // ---------------------
  680.         // |B|B|B|B|B|P|P|P|P|P|
  681.         // ---------------^-^-^-
  682.        
  683.         BOOL found = NO;
  684.        
  685.         NSUInteger termLength = [term length];
  686.         NSUInteger preBufferLength = [preBuffer availableBytes];
  687.        
  688.         if ((bytesDone + preBufferLength) < termLength)
  689.         {
  690.                 // Not enough data for a full term sequence yet
  691.                 return preBufferLength;
  692.         }
  693.        
  694.         NSUInteger maxPreBufferLength;
  695.         if (maxLength > 0) {
  696.                 maxPreBufferLength = MIN(preBufferLength, (maxLength - bytesDone));
  697.                
  698.                 // Note: maxLength >= termLength
  699.         }
  700.         else {
  701.                 maxPreBufferLength = preBufferLength;
  702.         }
  703.        
  704.         uint8_t seq[termLength];
  705.         const void *termBuf = [term bytes];
  706.        
  707.         NSUInteger bufLen = MIN(bytesDone, (termLength - 1));
  708.         uint8_t *buf = (uint8_t *)[buffer mutableBytes] + startOffset + bytesDone - bufLen;
  709.        
  710.         NSUInteger preLen = termLength - bufLen;
  711.         const uint8_t *pre = [preBuffer readBuffer];
  712.        
  713.         NSUInteger loopCount = bufLen + maxPreBufferLength - termLength + 1; // Plus one. See example above.
  714.        
  715.         NSUInteger result = maxPreBufferLength;
  716.        
  717.         NSUInteger i;
  718.         for (i = 0; i < loopCount; i++)
  719.         {
  720.                 if (bufLen > 0)
  721.                 {
  722.                         // Combining bytes from buffer and preBuffer
  723.                        
  724.                         memcpy(seq, buf, bufLen);
  725.                         memcpy(seq + bufLen, pre, preLen);
  726.                        
  727.                         if (memcmp(seq, termBuf, termLength) == 0)
  728.                         {
  729.                                 result = preLen;
  730.                                 found = YES;
  731.                                 break;
  732.                         }
  733.                        
  734.                         buf++;
  735.                         bufLen--;
  736.                         preLen++;
  737.                 }
  738.                 else
  739.                 {
  740.                         // Comparing directly from preBuffer
  741.                        
  742.                         if (memcmp(pre, termBuf, termLength) == 0)
  743.                         {
  744.                                 NSUInteger preOffset = pre - [preBuffer readBuffer]; // pointer arithmetic
  745.                                
  746.                                 result = preOffset + termLength;
  747.                                 found = YES;
  748.                                 break;
  749.                         }
  750.                        
  751.                         pre++;
  752.                 }
  753.         }
  754.        
  755.         // There is no need to avoid resizing the buffer in this particular situation.
  756.        
  757.         if (foundPtr) *foundPtr = found;
  758.         return result;
  759. }
  760.  
  761. /**
  762.  * For read packets with a set terminator, scans the packet buffer for the term.
  763.  * It is assumed the terminator had not been fully read prior to the new bytes.
  764.  *
  765.  * If the term is found, the number of excess bytes after the term are returned.
  766.  * If the term is not found, this method will return -1.
  767.  *
  768.  * Note: A return value of zero means the term was found at the very end.
  769.  *
  770.  * Prerequisites:
  771.  * The given number of bytes have been added to the end of our buffer.
  772.  * Our bytesDone variable has NOT been changed due to the prebuffered bytes.
  773. **/
  774. - (NSInteger)searchForTermAfterPreBuffering:(ssize_t)numBytes
  775. {
  776.         NSAssert(term != nil, @"This method does not apply to non-term reads");
  777.        
  778.         // The implementation of this method is very similar to the above method.
  779.         // See the above method for a discussion of the algorithm used here.
  780.        
  781.         uint8_t *buff = [buffer mutableBytes];
  782.         NSUInteger buffLength = bytesDone + numBytes;
  783.        
  784.         const void *termBuff = [term bytes];
  785.         NSUInteger termLength = [term length];
  786.        
  787.         // Note: We are dealing with unsigned integers,
  788.         // so make sure the math doesn't go below zero.
  789.        
  790.         NSUInteger i = ((buffLength - numBytes) >= termLength) ? (buffLength - numBytes - termLength + 1) : 0;
  791.        
  792.         while (i + termLength <= buffLength)
  793.         {
  794.                 uint8_t *subBuffer = buff + startOffset + i;
  795.                
  796.                 if (memcmp(subBuffer, termBuff, termLength) == 0)
  797.                 {
  798.                         return buffLength - (i + termLength);
  799.                 }
  800.                
  801.                 i++;
  802.         }
  803.        
  804.         return -1;
  805. }
  806.  
  807.  
  808. @end
  809.  
  810. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  811. #pragma mark -
  812. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  813.  
  814. /**
  815.  * The GCDAsyncWritePacket encompasses the instructions for any given write.
  816. **/
  817. @interface GCDAsyncWritePacket : NSObject
  818. {
  819.   @public
  820.         NSData *buffer;
  821.         NSUInteger bytesDone;
  822.         long tag;
  823.         NSTimeInterval timeout;
  824. }
  825. - (instancetype)initWithData:(NSData *)d timeout:(NSTimeInterval)t tag:(long)i NS_DESIGNATED_INITIALIZER;
  826. @end
  827.  
  828. @implementation GCDAsyncWritePacket
  829.  
  830. // Cover the superclass' designated initializer
  831. - (instancetype)init NS_UNAVAILABLE
  832. {
  833.         NSAssert(0, @"Use the designated initializer");
  834.         return nil;
  835. }
  836.  
  837. - (instancetype)initWithData:(NSData *)d timeout:(NSTimeInterval)t tag:(long)i
  838. {
  839.         if((self = [super init]))
  840.         {
  841.                 buffer = d; // Retain not copy. For performance as documented in header file.
  842.                 bytesDone = 0;
  843.                 timeout = t;
  844.                 tag = i;
  845.         }
  846.         return self;
  847. }
  848.  
  849.  
  850. @end
  851.  
  852. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  853. #pragma mark -
  854. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  855.  
  856. /**
  857.  * The GCDAsyncSpecialPacket encompasses special instructions for interruptions in the read/write queues.
  858.  * This class my be altered to support more than just TLS in the future.
  859. **/
  860. @interface GCDAsyncSpecialPacket : NSObject
  861. {
  862.   @public
  863.         NSDictionary *tlsSettings;
  864. }
  865. - (instancetype)initWithTLSSettings:(NSDictionary <NSString*,NSObject*>*)settings NS_DESIGNATED_INITIALIZER;
  866. @end
  867.  
  868. @implementation GCDAsyncSpecialPacket
  869.  
  870. // Cover the superclass' designated initializer
  871. - (instancetype)init NS_UNAVAILABLE
  872. {
  873.         NSAssert(0, @"Use the designated initializer");
  874.         return nil;
  875. }
  876.  
  877. - (instancetype)initWithTLSSettings:(NSDictionary <NSString*,NSObject*>*)settings
  878. {
  879.         if((self = [super init]))
  880.         {
  881.                 tlsSettings = [settings copy];
  882.         }
  883.         return self;
  884. }
  885.  
  886.  
  887. @end
  888.  
  889. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  890. #pragma mark -
  891. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  892.  
  893. @implementation GCDAsyncSocket
  894. {
  895.         uint32_t flags;
  896.         uint16_t config;
  897.        
  898.         __weak id<GCDAsyncSocketDelegate> delegate;
  899.         dispatch_queue_t delegateQueue;
  900.        
  901.         int socket4FD;
  902.         int socket6FD;
  903.         int socketUN;
  904.         NSURL *socketUrl;
  905.         int stateIndex;
  906.         NSData * connectInterface4;
  907.         NSData * connectInterface6;
  908.         NSData * connectInterfaceUN;
  909.        
  910.         dispatch_queue_t socketQueue;
  911.        
  912.         dispatch_source_t accept4Source;
  913.         dispatch_source_t accept6Source;
  914.         dispatch_source_t acceptUNSource;
  915.         dispatch_source_t connectTimer;
  916.         dispatch_source_t readSource;
  917.         dispatch_source_t writeSource;
  918.         dispatch_source_t readTimer;
  919.         dispatch_source_t writeTimer;
  920.        
  921.         NSMutableArray *readQueue;
  922.         NSMutableArray *writeQueue;
  923.        
  924.         GCDAsyncReadPacket *currentRead;
  925.         GCDAsyncWritePacket *currentWrite;
  926.        
  927.         unsigned long socketFDBytesAvailable;
  928.        
  929.         GCDAsyncSocketPreBuffer *preBuffer;
  930.                
  931. #if TARGET_OS_IPHONE
  932.         CFStreamClientContext streamContext;
  933.         CFReadStreamRef readStream;
  934.         CFWriteStreamRef writeStream;
  935. #endif
  936.         SSLContextRef sslContext;
  937.         GCDAsyncSocketPreBuffer *sslPreBuffer;
  938.         size_t sslWriteCachedLength;
  939.         OSStatus sslErrCode;
  940.     OSStatus lastSSLHandshakeError;
  941.        
  942.         void *IsOnSocketQueueOrTargetQueueKey;
  943.        
  944.         id userData;
  945.     NSTimeInterval alternateAddressDelay;
  946. }
  947.  
  948. - (instancetype)init
  949. {
  950.         return [self initWithDelegate:nil delegateQueue:NULL socketQueue:NULL];
  951. }
  952.  
  953. - (instancetype)initWithSocketQueue:(dispatch_queue_t)sq
  954. {
  955.         return [self initWithDelegate:nil delegateQueue:NULL socketQueue:sq];
  956. }
  957.  
  958. - (instancetype)initWithDelegate:(id<GCDAsyncSocketDelegate>)aDelegate delegateQueue:(dispatch_queue_t)dq
  959. {
  960.         return [self initWithDelegate:aDelegate delegateQueue:dq socketQueue:NULL];
  961. }
  962.  
  963. - (instancetype)initWithDelegate:(id<GCDAsyncSocketDelegate>)aDelegate delegateQueue:(dispatch_queue_t)dq socketQueue:(dispatch_queue_t)sq
  964. {
  965.         if((self = [super init]))
  966.         {
  967.                 delegate = aDelegate;
  968.                 delegateQueue = dq;
  969.                
  970.                 #if !OS_OBJECT_USE_OBJC
  971.                 if (dq) dispatch_retain(dq);
  972.                 #endif
  973.                
  974.                 socket4FD = SOCKET_NULL;
  975.                 socket6FD = SOCKET_NULL;
  976.                 socketUN = SOCKET_NULL;
  977.                 socketUrl = nil;
  978.                 stateIndex = 0;
  979.                
  980.                 if (sq)
  981.                 {
  982.                         NSAssert(sq != dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0),
  983.                                  @"The given socketQueue parameter must not be a concurrent queue.");
  984.                         NSAssert(sq != dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0),
  985.                                  @"The given socketQueue parameter must not be a concurrent queue.");
  986.                         NSAssert(sq != dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),
  987.                                  @"The given socketQueue parameter must not be a concurrent queue.");
  988.                        
  989.                         socketQueue = sq;
  990.                         #if !OS_OBJECT_USE_OBJC
  991.                         dispatch_retain(sq);
  992.                         #endif
  993.                 }
  994.                 else
  995.                 {
  996.                         socketQueue = dispatch_queue_create([GCDAsyncSocketQueueName UTF8String], NULL);
  997.                 }
  998.                
  999.                 // The dispatch_queue_set_specific() and dispatch_get_specific() functions take a "void *key" parameter.
  1000.                 // From the documentation:
  1001.                 //
  1002.                 // > Keys are only compared as pointers and are never dereferenced.
  1003.                 // > Thus, you can use a pointer to a static variable for a specific subsystem or
  1004.                 // > any other value that allows you to identify the value uniquely.
  1005.                 //
  1006.                 // We're just going to use the memory address of an ivar.
  1007.                 // Specifically an ivar that is explicitly named for our purpose to make the code more readable.
  1008.                 //
  1009.                 // However, it feels tedious (and less readable) to include the "&" all the time:
  1010.                 // dispatch_get_specific(&IsOnSocketQueueOrTargetQueueKey)
  1011.                 //
  1012.                 // So we're going to make it so it doesn't matter if we use the '&' or not,
  1013.                 // by assigning the value of the ivar to the address of the ivar.
  1014.                 // Thus: IsOnSocketQueueOrTargetQueueKey == &IsOnSocketQueueOrTargetQueueKey;
  1015.                
  1016.                 IsOnSocketQueueOrTargetQueueKey = &IsOnSocketQueueOrTargetQueueKey;
  1017.                
  1018.                 void *nonNullUnusedPointer = (__bridge void *)self;
  1019.                 dispatch_queue_set_specific(socketQueue, IsOnSocketQueueOrTargetQueueKey, nonNullUnusedPointer, NULL);
  1020.                
  1021.                 readQueue = [[NSMutableArray alloc] initWithCapacity:5];
  1022.                 currentRead = nil;
  1023.                
  1024.                 writeQueue = [[NSMutableArray alloc] initWithCapacity:5];
  1025.                 currentWrite = nil;
  1026.                
  1027.                 preBuffer = [[GCDAsyncSocketPreBuffer alloc] initWithCapacity:(1024 * 4)];
  1028.         alternateAddressDelay = 0.3;
  1029.         }
  1030.         return self;
  1031. }
  1032.  
  1033. - (void)dealloc
  1034. {
  1035.         LogInfo(@"%@ - %@ (start)", THIS_METHOD, self);
  1036.        
  1037.         // Set dealloc flag.
  1038.         // This is used by closeWithError to ensure we don't accidentally retain ourself.
  1039.         flags |= kDealloc;
  1040.        
  1041.         if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
  1042.         {
  1043.                 [self closeWithError:nil];
  1044.         }
  1045.         else
  1046.         {
  1047.                 dispatch_sync(socketQueue, ^{
  1048.                         [self closeWithError:nil];
  1049.                 });
  1050.         }
  1051.        
  1052.         delegate = nil;
  1053.        
  1054.         #if !OS_OBJECT_USE_OBJC
  1055.         if (delegateQueue) dispatch_release(delegateQueue);
  1056.         #endif
  1057.         delegateQueue = NULL;
  1058.        
  1059.         #if !OS_OBJECT_USE_OBJC
  1060.         if (socketQueue) dispatch_release(socketQueue);
  1061.         #endif
  1062.         socketQueue = NULL;
  1063.        
  1064.         LogInfo(@"%@ - %@ (finish)", THIS_METHOD, self);
  1065. }
  1066.  
  1067. #pragma mark -
  1068.  
  1069. + (nullable instancetype)socketFromConnectedSocketFD:(int)socketFD socketQueue:(nullable dispatch_queue_t)sq error:(NSError**)error {
  1070.   return [self socketFromConnectedSocketFD:socketFD delegate:nil delegateQueue:NULL socketQueue:sq error:error];
  1071. }
  1072.  
  1073. + (nullable instancetype)socketFromConnectedSocketFD:(int)socketFD delegate:(nullable id<GCDAsyncSocketDelegate>)aDelegate delegateQueue:(nullable dispatch_queue_t)dq error:(NSError**)error {
  1074.   return [self socketFromConnectedSocketFD:socketFD delegate:aDelegate delegateQueue:dq socketQueue:NULL error:error];
  1075. }
  1076.  
  1077. + (nullable instancetype)socketFromConnectedSocketFD:(int)socketFD delegate:(nullable id<GCDAsyncSocketDelegate>)aDelegate delegateQueue:(nullable dispatch_queue_t)dq socketQueue:(nullable dispatch_queue_t)sq error:(NSError* __autoreleasing *)error
  1078. {
  1079.   __block BOOL errorOccured = NO;
  1080.  
  1081.   GCDAsyncSocket *socket = [[[self class] alloc] initWithDelegate:aDelegate delegateQueue:dq socketQueue:sq];
  1082.  
  1083.   dispatch_sync(socket->socketQueue, ^{ @autoreleasepool {
  1084.     struct sockaddr addr;
  1085.     socklen_t addr_size = sizeof(struct sockaddr);
  1086.     int retVal = getpeername(socketFD, (struct sockaddr *)&addr, &addr_size);
  1087.     if (retVal)
  1088.     {
  1089.       NSString *errMsg = NSLocalizedStringWithDefaultValue(@"GCDAsyncSocketOtherError",
  1090.                                                            @"GCDAsyncSocket", [NSBundle mainBundle],
  1091.                                                            @"Attempt to create socket from socket FD failed. getpeername() failed", nil);
  1092.      
  1093.       NSDictionary *userInfo = @{NSLocalizedDescriptionKey : errMsg};
  1094.  
  1095.       errorOccured = YES;
  1096.       if (error)
  1097.         *error = [NSError errorWithDomain:GCDAsyncSocketErrorDomain code:GCDAsyncSocketOtherError userInfo:userInfo];
  1098.       return;
  1099.     }
  1100.    
  1101.     if (addr.sa_family == AF_INET)
  1102.     {
  1103.       socket->socket4FD = socketFD;
  1104.     }
  1105.     else if (addr.sa_family == AF_INET6)
  1106.     {
  1107.       socket->socket6FD = socketFD;
  1108.     }
  1109.     else
  1110.     {
  1111.       NSString *errMsg = NSLocalizedStringWithDefaultValue(@"GCDAsyncSocketOtherError",
  1112.                                                            @"GCDAsyncSocket", [NSBundle mainBundle],
  1113.                                                            @"Attempt to create socket from socket FD failed. socket FD is neither IPv4 nor IPv6", nil);
  1114.      
  1115.       NSDictionary *userInfo = @{NSLocalizedDescriptionKey : errMsg};
  1116.      
  1117.       errorOccured = YES;
  1118.       if (error)
  1119.         *error = [NSError errorWithDomain:GCDAsyncSocketErrorDomain code:GCDAsyncSocketOtherError userInfo:userInfo];
  1120.       return;
  1121.     }
  1122.    
  1123.     socket->flags = kSocketStarted;
  1124.     [socket didConnect:socket->stateIndex];
  1125.   }});
  1126.  
  1127.   return errorOccured? nil: socket;
  1128. }
  1129.  
  1130. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1131. #pragma mark Configuration
  1132. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1133.  
  1134. - (id)delegate
  1135. {
  1136.         if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
  1137.         {
  1138.                 return delegate;
  1139.         }
  1140.         else
  1141.         {
  1142.                 __block id result;
  1143.                
  1144.                 dispatch_sync(socketQueue, ^{
  1145.             result = self->delegate;
  1146.                 });
  1147.                
  1148.                 return result;
  1149.         }
  1150. }
  1151.  
  1152. - (void)setDelegate:(id)newDelegate synchronously:(BOOL)synchronously
  1153. {
  1154.         dispatch_block_t block = ^{
  1155.         self->delegate = newDelegate;
  1156.         };
  1157.        
  1158.         if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) {
  1159.                 block();
  1160.         }
  1161.         else {
  1162.                 if (synchronously)
  1163.                         dispatch_sync(socketQueue, block);
  1164.                 else
  1165.                         dispatch_async(socketQueue, block);
  1166.         }
  1167. }
  1168.  
  1169. - (void)setDelegate:(id<GCDAsyncSocketDelegate>)newDelegate
  1170. {
  1171.         [self setDelegate:newDelegate synchronously:NO];
  1172. }
  1173.  
  1174. - (void)synchronouslySetDelegate:(id<GCDAsyncSocketDelegate>)newDelegate
  1175. {
  1176.         [self setDelegate:newDelegate synchronously:YES];
  1177. }
  1178.  
  1179. - (dispatch_queue_t)delegateQueue
  1180. {
  1181.         if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
  1182.         {
  1183.                 return delegateQueue;
  1184.         }
  1185.         else
  1186.         {
  1187.                 __block dispatch_queue_t result;
  1188.                
  1189.                 dispatch_sync(socketQueue, ^{
  1190.             result = self->delegateQueue;
  1191.                 });
  1192.                
  1193.                 return result;
  1194.         }
  1195. }
  1196.  
  1197. - (void)setDelegateQueue:(dispatch_queue_t)newDelegateQueue synchronously:(BOOL)synchronously
  1198. {
  1199.         dispatch_block_t block = ^{
  1200.                
  1201.                 #if !OS_OBJECT_USE_OBJC
  1202.         if (self->delegateQueue) dispatch_release(self->delegateQueue);
  1203.                 if (newDelegateQueue) dispatch_retain(newDelegateQueue);
  1204.                 #endif
  1205.                
  1206.         self->delegateQueue = newDelegateQueue;
  1207.         };
  1208.        
  1209.         if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) {
  1210.                 block();
  1211.         }
  1212.         else {
  1213.                 if (synchronously)
  1214.                         dispatch_sync(socketQueue, block);
  1215.                 else
  1216.                         dispatch_async(socketQueue, block);
  1217.         }
  1218. }
  1219.  
  1220. - (void)setDelegateQueue:(dispatch_queue_t)newDelegateQueue
  1221. {
  1222.         [self setDelegateQueue:newDelegateQueue synchronously:NO];
  1223. }
  1224.  
  1225. - (void)synchronouslySetDelegateQueue:(dispatch_queue_t)newDelegateQueue
  1226. {
  1227.         [self setDelegateQueue:newDelegateQueue synchronously:YES];
  1228. }
  1229.  
  1230. - (void)getDelegate:(id<GCDAsyncSocketDelegate> *)delegatePtr delegateQueue:(dispatch_queue_t *)delegateQueuePtr
  1231. {
  1232.         if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
  1233.         {
  1234.                 if (delegatePtr) *delegatePtr = delegate;
  1235.                 if (delegateQueuePtr) *delegateQueuePtr = delegateQueue;
  1236.         }
  1237.         else
  1238.         {
  1239.                 __block id dPtr = NULL;
  1240.                 __block dispatch_queue_t dqPtr = NULL;
  1241.                
  1242.                 dispatch_sync(socketQueue, ^{
  1243.             dPtr = self->delegate;
  1244.             dqPtr = self->delegateQueue;
  1245.                 });
  1246.                
  1247.                 if (delegatePtr) *delegatePtr = dPtr;
  1248.                 if (delegateQueuePtr) *delegateQueuePtr = dqPtr;
  1249.         }
  1250. }
  1251.  
  1252. - (void)setDelegate:(id)newDelegate delegateQueue:(dispatch_queue_t)newDelegateQueue synchronously:(BOOL)synchronously
  1253. {
  1254.         dispatch_block_t block = ^{
  1255.                
  1256.         self->delegate = newDelegate;
  1257.                
  1258.                 #if !OS_OBJECT_USE_OBJC
  1259.         if (self->delegateQueue) dispatch_release(self->delegateQueue);
  1260.                 if (newDelegateQueue) dispatch_retain(newDelegateQueue);
  1261.                 #endif
  1262.                
  1263.         self->delegateQueue = newDelegateQueue;
  1264.         };
  1265.        
  1266.         if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) {
  1267.                 block();
  1268.         }
  1269.         else {
  1270.                 if (synchronously)
  1271.                         dispatch_sync(socketQueue, block);
  1272.                 else
  1273.                         dispatch_async(socketQueue, block);
  1274.         }
  1275. }
  1276.  
  1277. - (void)setDelegate:(id<GCDAsyncSocketDelegate>)newDelegate delegateQueue:(dispatch_queue_t)newDelegateQueue
  1278. {
  1279.         [self setDelegate:newDelegate delegateQueue:newDelegateQueue synchronously:NO];
  1280. }
  1281.  
  1282. - (void)synchronouslySetDelegate:(id<GCDAsyncSocketDelegate>)newDelegate delegateQueue:(dispatch_queue_t)newDelegateQueue
  1283. {
  1284.         [self setDelegate:newDelegate delegateQueue:newDelegateQueue synchronously:YES];
  1285. }
  1286.  
  1287. - (BOOL)isIPv4Enabled
  1288. {
  1289.         // Note: YES means kIPv4Disabled is OFF
  1290.        
  1291.         if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
  1292.         {
  1293.                 return ((config & kIPv4Disabled) == 0);
  1294.         }
  1295.         else
  1296.         {
  1297.                 __block BOOL result;
  1298.                
  1299.                 dispatch_sync(socketQueue, ^{
  1300.             result = ((self->config & kIPv4Disabled) == 0);
  1301.                 });
  1302.                
  1303.                 return result;
  1304.         }
  1305. }
  1306.  
  1307. - (void)setIPv4Enabled:(BOOL)flag
  1308. {
  1309.         // Note: YES means kIPv4Disabled is OFF
  1310.        
  1311.         dispatch_block_t block = ^{
  1312.                
  1313.                 if (flag)
  1314.             self->config &= ~kIPv4Disabled;
  1315.                 else
  1316.             self->config |= kIPv4Disabled;
  1317.         };
  1318.        
  1319.         if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
  1320.                 block();
  1321.         else
  1322.                 dispatch_async(socketQueue, block);
  1323. }
  1324.  
  1325. - (BOOL)isIPv6Enabled
  1326. {
  1327.         // Note: YES means kIPv6Disabled is OFF
  1328.        
  1329.         if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
  1330.         {
  1331.                 return ((config & kIPv6Disabled) == 0);
  1332.         }
  1333.         else
  1334.         {
  1335.                 __block BOOL result;
  1336.                
  1337.                 dispatch_sync(socketQueue, ^{
  1338.             result = ((self->config & kIPv6Disabled) == 0);
  1339.                 });
  1340.                
  1341.                 return result;
  1342.         }
  1343. }
  1344.  
  1345. - (void)setIPv6Enabled:(BOOL)flag
  1346. {
  1347.         // Note: YES means kIPv6Disabled is OFF
  1348.        
  1349.         dispatch_block_t block = ^{
  1350.                
  1351.                 if (flag)
  1352.             self->config &= ~kIPv6Disabled;
  1353.                 else
  1354.             self->config |= kIPv6Disabled;
  1355.         };
  1356.        
  1357.         if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
  1358.                 block();
  1359.         else
  1360.                 dispatch_async(socketQueue, block);
  1361. }
  1362.  
  1363. - (BOOL)isIPv4PreferredOverIPv6
  1364. {
  1365.         // Note: YES means kPreferIPv6 is OFF
  1366.        
  1367.         if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
  1368.         {
  1369.                 return ((config & kPreferIPv6) == 0);
  1370.         }
  1371.         else
  1372.         {
  1373.                 __block BOOL result;
  1374.                
  1375.                 dispatch_sync(socketQueue, ^{
  1376.             result = ((self->config & kPreferIPv6) == 0);
  1377.                 });
  1378.                
  1379.                 return result;
  1380.         }
  1381. }
  1382.  
  1383. - (void)setIPv4PreferredOverIPv6:(BOOL)flag
  1384. {
  1385.         // Note: YES means kPreferIPv6 is OFF
  1386.        
  1387.         dispatch_block_t block = ^{
  1388.                
  1389.                 if (flag)
  1390.             self->config &= ~kPreferIPv6;
  1391.                 else
  1392.             self->config |= kPreferIPv6;
  1393.         };
  1394.        
  1395.         if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
  1396.                 block();
  1397.         else
  1398.                 dispatch_async(socketQueue, block);
  1399. }
  1400.  
  1401. - (NSTimeInterval) alternateAddressDelay {
  1402.     __block NSTimeInterval delay;
  1403.     dispatch_block_t block = ^{
  1404.         delay = self->alternateAddressDelay;
  1405.     };
  1406.     if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
  1407.         block();
  1408.     else
  1409.         dispatch_sync(socketQueue, block);
  1410.     return delay;
  1411. }
  1412.  
  1413. - (void) setAlternateAddressDelay:(NSTimeInterval)delay {
  1414.     dispatch_block_t block = ^{
  1415.         self->alternateAddressDelay = delay;
  1416.     };
  1417.     if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
  1418.         block();
  1419.     else
  1420.         dispatch_async(socketQueue, block);
  1421. }
  1422.  
  1423. - (id)userData
  1424. {
  1425.         __block id result = nil;
  1426.        
  1427.         dispatch_block_t block = ^{
  1428.                
  1429.         result = self->userData;
  1430.         };
  1431.        
  1432.         if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
  1433.                 block();
  1434.         else
  1435.                 dispatch_sync(socketQueue, block);
  1436.        
  1437.         return result;
  1438. }
  1439.  
  1440. - (void)setUserData:(id)arbitraryUserData
  1441. {
  1442.         dispatch_block_t block = ^{
  1443.                
  1444.         if (self->userData != arbitraryUserData)
  1445.                 {
  1446.             self->userData = arbitraryUserData;
  1447.                 }
  1448.         };
  1449.        
  1450.         if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
  1451.                 block();
  1452.         else
  1453.                 dispatch_async(socketQueue, block);
  1454. }
  1455.  
  1456. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1457. #pragma mark Accepting
  1458. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1459.  
  1460. - (BOOL)acceptOnPort:(uint16_t)port error:(NSError **)errPtr
  1461. {
  1462.         return [self acceptOnInterface:nil port:port error:errPtr];
  1463. }
  1464.  
  1465. - (BOOL)acceptOnInterface:(NSString *)inInterface port:(uint16_t)port error:(NSError **)errPtr
  1466. {
  1467.         LogTrace();
  1468.        
  1469.         // Just in-case interface parameter is immutable.
  1470.         NSString *interface = [inInterface copy];
  1471.        
  1472.         __block BOOL result = NO;
  1473.         __block NSError *err = nil;
  1474.        
  1475.         // CreateSocket Block
  1476.         // This block will be invoked within the dispatch block below.
  1477.        
  1478.         int(^createSocket)(int, NSData*) = ^int (int domain, NSData *interfaceAddr) {
  1479.                
  1480.                 int socketFD = socket(domain, SOCK_STREAM, 0);
  1481.                
  1482.                 if (socketFD == SOCKET_NULL)
  1483.                 {
  1484.                         NSString *reason = @"Error in socket() function";
  1485.                         err = [self errorWithErrno:errno reason:reason];
  1486.                        
  1487.                         return SOCKET_NULL;
  1488.                 }
  1489.                
  1490.                 int status;
  1491.                
  1492.                 // Set socket options
  1493.                
  1494.                 status = fcntl(socketFD, F_SETFL, O_NONBLOCK);
  1495.                 if (status == -1)
  1496.                 {
  1497.                         NSString *reason = @"Error enabling non-blocking IO on socket (fcntl)";
  1498.                         err = [self errorWithErrno:errno reason:reason];
  1499.                        
  1500.                         LogVerbose(@"close(socketFD)");
  1501.                         close(socketFD);
  1502.                         return SOCKET_NULL;
  1503.                 }
  1504.                
  1505.                 int reuseOn = 1;
  1506.                 status = setsockopt(socketFD, SOL_SOCKET, SO_REUSEADDR, &reuseOn, sizeof(reuseOn));
  1507.                 if (status == -1)
  1508.                 {
  1509.                         NSString *reason = @"Error enabling address reuse (setsockopt)";
  1510.                         err = [self errorWithErrno:errno reason:reason];
  1511.                        
  1512.                         LogVerbose(@"close(socketFD)");
  1513.                         close(socketFD);
  1514.                         return SOCKET_NULL;
  1515.                 }
  1516.                
  1517.                 // Bind socket
  1518.                
  1519.                 status = bind(socketFD, (const struct sockaddr *)[interfaceAddr bytes], (socklen_t)[interfaceAddr length]);
  1520.                 if (status == -1)
  1521.                 {
  1522.                         NSString *reason = @"Error in bind() function";
  1523.                         err = [self errorWithErrno:errno reason:reason];
  1524.                        
  1525.                         LogVerbose(@"close(socketFD)");
  1526.                         close(socketFD);
  1527.                         return SOCKET_NULL;
  1528.                 }
  1529.                
  1530.                 // Listen
  1531.                
  1532.                 status = listen(socketFD, 1024);
  1533.                 if (status == -1)
  1534.                 {
  1535.                         NSString *reason = @"Error in listen() function";
  1536.                         err = [self errorWithErrno:errno reason:reason];
  1537.                        
  1538.                         LogVerbose(@"close(socketFD)");
  1539.                         close(socketFD);
  1540.                         return SOCKET_NULL;
  1541.                 }
  1542.                
  1543.                 return socketFD;
  1544.         };
  1545.        
  1546.         // Create dispatch block and run on socketQueue
  1547.        
  1548.         dispatch_block_t block = ^{ @autoreleasepool {
  1549.                
  1550.         if (self->delegate == nil) // Must have delegate set
  1551.                 {
  1552.                         NSString *msg = @"Attempting to accept without a delegate. Set a delegate first.";
  1553.                         err = [self badConfigError:msg];
  1554.                        
  1555.                         return_from_block;
  1556.                 }
  1557.                
  1558.         if (self->delegateQueue == NULL) // Must have delegate queue set
  1559.                 {
  1560.                         NSString *msg = @"Attempting to accept without a delegate queue. Set a delegate queue first.";
  1561.                         err = [self badConfigError:msg];
  1562.                        
  1563.                         return_from_block;
  1564.                 }
  1565.                
  1566.         BOOL isIPv4Disabled = (self->config & kIPv4Disabled) ? YES : NO;
  1567.         BOOL isIPv6Disabled = (self->config & kIPv6Disabled) ? YES : NO;
  1568.                
  1569.                 if (isIPv4Disabled && isIPv6Disabled) // Must have IPv4 or IPv6 enabled
  1570.                 {
  1571.                         NSString *msg = @"Both IPv4 and IPv6 have been disabled. Must enable at least one protocol first.";
  1572.                         err = [self badConfigError:msg];
  1573.                        
  1574.                         return_from_block;
  1575.                 }
  1576.                
  1577.                 if (![self isDisconnected]) // Must be disconnected
  1578.                 {
  1579.                         NSString *msg = @"Attempting to accept while connected or accepting connections. Disconnect first.";
  1580.                         err = [self badConfigError:msg];
  1581.                        
  1582.                         return_from_block;
  1583.                 }
  1584.                
  1585.                 // Clear queues (spurious read/write requests post disconnect)
  1586.         [self->readQueue removeAllObjects];
  1587.         [self->writeQueue removeAllObjects];
  1588.                
  1589.                 // Resolve interface from description
  1590.                
  1591.                 NSMutableData *interface4 = nil;
  1592.                 NSMutableData *interface6 = nil;
  1593.                
  1594.                 [self getInterfaceAddress4:&interface4 address6:&interface6 fromDescription:interface port:port];
  1595.                
  1596.                 if ((interface4 == nil) && (interface6 == nil))
  1597.                 {
  1598.                         NSString *msg = @"Unknown interface. Specify valid interface by name (e.g. \"en1\") or IP address.";
  1599.                         err = [self badParamError:msg];
  1600.                        
  1601.                         return_from_block;
  1602.                 }
  1603.                
  1604.                 if (isIPv4Disabled && (interface6 == nil))
  1605.                 {
  1606.                         NSString *msg = @"IPv4 has been disabled and specified interface doesn't support IPv6.";
  1607.                         err = [self badParamError:msg];
  1608.                        
  1609.                         return_from_block;
  1610.                 }
  1611.                
  1612.                 if (isIPv6Disabled && (interface4 == nil))
  1613.                 {
  1614.                         NSString *msg = @"IPv6 has been disabled and specified interface doesn't support IPv4.";
  1615.                         err = [self badParamError:msg];
  1616.                        
  1617.                         return_from_block;
  1618.                 }
  1619.                
  1620.                 BOOL enableIPv4 = !isIPv4Disabled && (interface4 != nil);
  1621.                 BOOL enableIPv6 = !isIPv6Disabled && (interface6 != nil);
  1622.                
  1623.                 // Create sockets, configure, bind, and listen
  1624.                
  1625.                 if (enableIPv4)
  1626.                 {
  1627.                         LogVerbose(@"Creating IPv4 socket");
  1628.             self->socket4FD = createSocket(AF_INET, interface4);
  1629.                        
  1630.             if (self->socket4FD == SOCKET_NULL)
  1631.                         {
  1632.                                 return_from_block;
  1633.                         }
  1634.                 }
  1635.                
  1636.                 if (enableIPv6)
  1637.                 {
  1638.                         LogVerbose(@"Creating IPv6 socket");
  1639.                        
  1640.                         if (enableIPv4 && (port == 0))
  1641.                         {
  1642.                                 // No specific port was specified, so we allowed the OS to pick an available port for us.
  1643.                                 // Now we need to make sure the IPv6 socket listens on the same port as the IPv4 socket.
  1644.                                
  1645.                                 struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)[interface6 mutableBytes];
  1646.                                 addr6->sin6_port = htons([self localPort4]);
  1647.                         }
  1648.                        
  1649.             self->socket6FD = createSocket(AF_INET6, interface6);
  1650.                        
  1651.             if (self->socket6FD == SOCKET_NULL)
  1652.                         {
  1653.                 if (self->socket4FD != SOCKET_NULL)
  1654.                                 {
  1655.                                         LogVerbose(@"close(socket4FD)");
  1656.                     close(self->socket4FD);
  1657.                     self->socket4FD = SOCKET_NULL;
  1658.                                 }
  1659.                                
  1660.                                 return_from_block;
  1661.                         }
  1662.                 }
  1663.                
  1664.                 // Create accept sources
  1665.                
  1666.                 if (enableIPv4)
  1667.                 {
  1668.             self->accept4Source = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, self->socket4FD, 0, self->socketQueue);
  1669.                        
  1670.             int socketFD = self->socket4FD;
  1671.             dispatch_source_t acceptSource = self->accept4Source;
  1672.                        
  1673.                         __weak GCDAsyncSocket *weakSelf = self;
  1674.                        
  1675.             dispatch_source_set_event_handler(self->accept4Source, ^{ @autoreleasepool {
  1676.                         #pragma clang diagnostic push
  1677.                         #pragma clang diagnostic warning "-Wimplicit-retain-self"
  1678.                                
  1679.                                 __strong GCDAsyncSocket *strongSelf = weakSelf;
  1680.                                 if (strongSelf == nil) return_from_block;
  1681.                                
  1682.                                 LogVerbose(@"event4Block");
  1683.                                
  1684.                                 unsigned long i = 0;
  1685.                                 unsigned long numPendingConnections = dispatch_source_get_data(acceptSource);
  1686.                                
  1687.                                 LogVerbose(@"numPendingConnections: %lu", numPendingConnections);
  1688.                                
  1689.                                 while ([strongSelf doAccept:socketFD] && (++i < numPendingConnections));
  1690.                                
  1691.                         #pragma clang diagnostic pop
  1692.                         }});
  1693.                        
  1694.                        
  1695.             dispatch_source_set_cancel_handler(self->accept4Source, ^{
  1696.                         #pragma clang diagnostic push
  1697.                         #pragma clang diagnostic warning "-Wimplicit-retain-self"
  1698.                                
  1699.                                 #if !OS_OBJECT_USE_OBJC
  1700.                                 LogVerbose(@"dispatch_release(accept4Source)");
  1701.                                 dispatch_release(acceptSource);
  1702.                                 #endif
  1703.                                
  1704.                                 LogVerbose(@"close(socket4FD)");
  1705.                                 close(socketFD);
  1706.                        
  1707.                         #pragma clang diagnostic pop
  1708.                         });
  1709.                        
  1710.                         LogVerbose(@"dispatch_resume(accept4Source)");
  1711.             dispatch_resume(self->accept4Source);
  1712.                 }
  1713.                
  1714.                 if (enableIPv6)
  1715.                 {
  1716.             self->accept6Source = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, self->socket6FD, 0, self->socketQueue);
  1717.                        
  1718.             int socketFD = self->socket6FD;
  1719.             dispatch_source_t acceptSource = self->accept6Source;
  1720.                        
  1721.                         __weak GCDAsyncSocket *weakSelf = self;
  1722.                        
  1723.             dispatch_source_set_event_handler(self->accept6Source, ^{ @autoreleasepool {
  1724.                         #pragma clang diagnostic push
  1725.                         #pragma clang diagnostic warning "-Wimplicit-retain-self"
  1726.                                
  1727.                                 __strong GCDAsyncSocket *strongSelf = weakSelf;
  1728.                                 if (strongSelf == nil) return_from_block;
  1729.                                
  1730.                                 LogVerbose(@"event6Block");
  1731.                                
  1732.                                 unsigned long i = 0;
  1733.                                 unsigned long numPendingConnections = dispatch_source_get_data(acceptSource);
  1734.                                
  1735.                                 LogVerbose(@"numPendingConnections: %lu", numPendingConnections);
  1736.                                
  1737.                                 while ([strongSelf doAccept:socketFD] && (++i < numPendingConnections));
  1738.                                
  1739.                         #pragma clang diagnostic pop
  1740.                         }});
  1741.                        
  1742.             dispatch_source_set_cancel_handler(self->accept6Source, ^{
  1743.                         #pragma clang diagnostic push
  1744.                         #pragma clang diagnostic warning "-Wimplicit-retain-self"
  1745.                                
  1746.                                 #if !OS_OBJECT_USE_OBJC
  1747.                                 LogVerbose(@"dispatch_release(accept6Source)");
  1748.                                 dispatch_release(acceptSource);
  1749.                                 #endif
  1750.                                
  1751.                                 LogVerbose(@"close(socket6FD)");
  1752.                                 close(socketFD);
  1753.                                
  1754.                         #pragma clang diagnostic pop
  1755.                         });
  1756.                        
  1757.                         LogVerbose(@"dispatch_resume(accept6Source)");
  1758.             dispatch_resume(self->accept6Source);
  1759.                 }
  1760.                
  1761.         self->flags |= kSocketStarted;
  1762.                
  1763.                 result = YES;
  1764.         }};
  1765.        
  1766.         if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
  1767.                 block();
  1768.         else
  1769.                 dispatch_sync(socketQueue, block);
  1770.        
  1771.         if (result == NO)
  1772.         {
  1773.                 LogInfo(@"Error in accept: %@", err);
  1774.                
  1775.                 if (errPtr)
  1776.                         *errPtr = err;
  1777.         }
  1778.        
  1779.         return result;
  1780. }
  1781.  
  1782. - (BOOL)acceptOnUrl:(NSURL *)url error:(NSError **)errPtr
  1783. {
  1784.         LogTrace();
  1785.        
  1786.         __block BOOL result = NO;
  1787.         __block NSError *err = nil;
  1788.        
  1789.         // CreateSocket Block
  1790.         // This block will be invoked within the dispatch block below.
  1791.        
  1792.         int(^createSocket)(int, NSData*) = ^int (int domain, NSData *interfaceAddr) {
  1793.                
  1794.                 int socketFD = socket(domain, SOCK_STREAM, 0);
  1795.                
  1796.                 if (socketFD == SOCKET_NULL)
  1797.                 {
  1798.                         NSString *reason = @"Error in socket() function";
  1799.                         err = [self errorWithErrno:errno reason:reason];
  1800.                        
  1801.                         return SOCKET_NULL;
  1802.                 }
  1803.                
  1804.                 int status;
  1805.                
  1806.                 // Set socket options
  1807.                
  1808.                 status = fcntl(socketFD, F_SETFL, O_NONBLOCK);
  1809.                 if (status == -1)
  1810.                 {
  1811.                         NSString *reason = @"Error enabling non-blocking IO on socket (fcntl)";
  1812.                         err = [self errorWithErrno:errno reason:reason];
  1813.                        
  1814.                         LogVerbose(@"close(socketFD)");
  1815.                         close(socketFD);
  1816.                         return SOCKET_NULL;
  1817.                 }
  1818.                
  1819.                 int reuseOn = 1;
  1820.                 status = setsockopt(socketFD, SOL_SOCKET, SO_REUSEADDR, &reuseOn, sizeof(reuseOn));
  1821.                 if (status == -1)
  1822.                 {
  1823.                         NSString *reason = @"Error enabling address reuse (setsockopt)";
  1824.                         err = [self errorWithErrno:errno reason:reason];
  1825.                        
  1826.                         LogVerbose(@"close(socketFD)");
  1827.                         close(socketFD);
  1828.                         return SOCKET_NULL;
  1829.                 }
  1830.                
  1831.                 // Bind socket
  1832.                
  1833.                 status = bind(socketFD, (const struct sockaddr *)[interfaceAddr bytes], (socklen_t)[interfaceAddr length]);
  1834.                 if (status == -1)
  1835.                 {
  1836.                         NSString *reason = @"Error in bind() function";
  1837.                         err = [self errorWithErrno:errno reason:reason];
  1838.                        
  1839.                         LogVerbose(@"close(socketFD)");
  1840.                         close(socketFD);
  1841.                         return SOCKET_NULL;
  1842.                 }
  1843.                
  1844.                 // Listen
  1845.                
  1846.                 status = listen(socketFD, 1024);
  1847.                 if (status == -1)
  1848.                 {
  1849.                         NSString *reason = @"Error in listen() function";
  1850.                         err = [self errorWithErrno:errno reason:reason];
  1851.                        
  1852.                         LogVerbose(@"close(socketFD)");
  1853.                         close(socketFD);
  1854.                         return SOCKET_NULL;
  1855.                 }
  1856.                
  1857.                 return socketFD;
  1858.         };
  1859.        
  1860.         // Create dispatch block and run on socketQueue
  1861.        
  1862.         dispatch_block_t block = ^{ @autoreleasepool {
  1863.                
  1864.         if (self->delegate == nil) // Must have delegate set
  1865.                 {
  1866.                         NSString *msg = @"Attempting to accept without a delegate. Set a delegate first.";
  1867.                         err = [self badConfigError:msg];
  1868.                        
  1869.                         return_from_block;
  1870.                 }
  1871.                
  1872.         if (self->delegateQueue == NULL) // Must have delegate queue set
  1873.                 {
  1874.                         NSString *msg = @"Attempting to accept without a delegate queue. Set a delegate queue first.";
  1875.                         err = [self badConfigError:msg];
  1876.                        
  1877.                         return_from_block;
  1878.                 }
  1879.                
  1880.                 if (![self isDisconnected]) // Must be disconnected
  1881.                 {
  1882.                         NSString *msg = @"Attempting to accept while connected or accepting connections. Disconnect first.";
  1883.                         err = [self badConfigError:msg];
  1884.                        
  1885.                         return_from_block;
  1886.                 }
  1887.                
  1888.                 // Clear queues (spurious read/write requests post disconnect)
  1889.         [self->readQueue removeAllObjects];
  1890.         [self->writeQueue removeAllObjects];
  1891.                
  1892.                 // Remove a previous socket
  1893.                
  1894.                 NSError *error = nil;
  1895.                 NSFileManager *fileManager = [NSFileManager defaultManager];
  1896.                 NSString *urlPath = url.path;
  1897.                 if (urlPath && [fileManager fileExistsAtPath:urlPath]) {
  1898.                         if (![fileManager removeItemAtURL:url error:&error]) {
  1899.                                 NSString *msg = @"Could not remove previous unix domain socket at given url.";
  1900.                                 err = [self otherError:msg];
  1901.                                
  1902.                                 return_from_block;
  1903.                         }
  1904.                 }
  1905.                
  1906.                 // Resolve interface from description
  1907.                
  1908.                 NSData *interface = [self getInterfaceAddressFromUrl:url];
  1909.                
  1910.                 if (interface == nil)
  1911.                 {
  1912.                         NSString *msg = @"Invalid unix domain url. Specify a valid file url that does not exist (e.g. \"file:///tmp/socket\")";
  1913.                         err = [self badParamError:msg];
  1914.                        
  1915.                         return_from_block;
  1916.                 }
  1917.                
  1918.                 // Create sockets, configure, bind, and listen
  1919.                
  1920.                 LogVerbose(@"Creating unix domain socket");
  1921.         self->socketUN = createSocket(AF_UNIX, interface);
  1922.                
  1923.         if (self->socketUN == SOCKET_NULL)
  1924.                 {
  1925.                         return_from_block;
  1926.                 }
  1927.                
  1928.         self->socketUrl = url;
  1929.                
  1930.                 // Create accept sources
  1931.                
  1932.         self->acceptUNSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, self->socketUN, 0, self->socketQueue);
  1933.                
  1934.         int socketFD = self->socketUN;
  1935.         dispatch_source_t acceptSource = self->acceptUNSource;
  1936.                
  1937.                 __weak GCDAsyncSocket *weakSelf = self;
  1938.                
  1939.         dispatch_source_set_event_handler(self->acceptUNSource, ^{ @autoreleasepool {
  1940.                        
  1941.                         __strong GCDAsyncSocket *strongSelf = weakSelf;
  1942.                        
  1943.                         LogVerbose(@"eventUNBlock");
  1944.                        
  1945.                         unsigned long i = 0;
  1946.                         unsigned long numPendingConnections = dispatch_source_get_data(acceptSource);
  1947.                        
  1948.                         LogVerbose(@"numPendingConnections: %lu", numPendingConnections);
  1949.                        
  1950.                         while ([strongSelf doAccept:socketFD] && (++i < numPendingConnections));
  1951.                 }});
  1952.                
  1953.         dispatch_source_set_cancel_handler(self->acceptUNSource, ^{
  1954.                        
  1955. #if !OS_OBJECT_USE_OBJC
  1956.                         LogVerbose(@"dispatch_release(acceptUNSource)");
  1957.                         dispatch_release(acceptSource);
  1958. #endif
  1959.                        
  1960.                         LogVerbose(@"close(socketUN)");
  1961.                         close(socketFD);
  1962.                 });
  1963.                
  1964.                 LogVerbose(@"dispatch_resume(acceptUNSource)");
  1965.         dispatch_resume(self->acceptUNSource);
  1966.                
  1967.         self->flags |= kSocketStarted;
  1968.                
  1969.                 result = YES;
  1970.         }};
  1971.        
  1972.         if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
  1973.                 block();
  1974.         else
  1975.                 dispatch_sync(socketQueue, block);
  1976.        
  1977.         if (result == NO)
  1978.         {
  1979.                 LogInfo(@"Error in accept: %@", err);
  1980.                
  1981.                 if (errPtr)
  1982.                         *errPtr = err;
  1983.         }
  1984.        
  1985.         return result; 
  1986. }
  1987.  
  1988. - (BOOL)doAccept:(int)parentSocketFD
  1989. {
  1990.         LogTrace();
  1991.        
  1992.         int socketType;
  1993.         int childSocketFD;
  1994.         NSData *childSocketAddress;
  1995.        
  1996.         if (parentSocketFD == socket4FD)
  1997.         {
  1998.                 socketType = 0;
  1999.                
  2000.                 struct sockaddr_in addr;
  2001.                 socklen_t addrLen = sizeof(addr);
  2002.                
  2003.                 childSocketFD = accept(parentSocketFD, (struct sockaddr *)&addr, &addrLen);
  2004.                
  2005.                 if (childSocketFD == -1)
  2006.                 {
  2007.                         LogWarn(@"Accept failed with error: %@", [self errnoError]);
  2008.                         return NO;
  2009.                 }
  2010.                
  2011.                 childSocketAddress = [NSData dataWithBytes:&addr length:addrLen];
  2012.         }
  2013.         else if (parentSocketFD == socket6FD)
  2014.         {
  2015.                 socketType = 1;
  2016.                
  2017.                 struct sockaddr_in6 addr;
  2018.                 socklen_t addrLen = sizeof(addr);
  2019.                
  2020.                 childSocketFD = accept(parentSocketFD, (struct sockaddr *)&addr, &addrLen);
  2021.                
  2022.                 if (childSocketFD == -1)
  2023.                 {
  2024.                         LogWarn(@"Accept failed with error: %@", [self errnoError]);
  2025.                         return NO;
  2026.                 }
  2027.                
  2028.                 childSocketAddress = [NSData dataWithBytes:&addr length:addrLen];
  2029.         }
  2030.         else // if (parentSocketFD == socketUN)
  2031.         {
  2032.                 socketType = 2;
  2033.                
  2034.                 struct sockaddr_un addr;
  2035.                 socklen_t addrLen = sizeof(addr);
  2036.                
  2037.                 childSocketFD = accept(parentSocketFD, (struct sockaddr *)&addr, &addrLen);
  2038.                
  2039.                 if (childSocketFD == -1)
  2040.                 {
  2041.                         LogWarn(@"Accept failed with error: %@", [self errnoError]);
  2042.                         return NO;
  2043.                 }
  2044.                
  2045.                 childSocketAddress = [NSData dataWithBytes:&addr length:addrLen];
  2046.         }
  2047.        
  2048.         // Enable non-blocking IO on the socket
  2049.        
  2050.         int result = fcntl(childSocketFD, F_SETFL, O_NONBLOCK);
  2051.         if (result == -1)
  2052.         {
  2053.                 LogWarn(@"Error enabling non-blocking IO on accepted socket (fcntl)");
  2054.                 LogVerbose(@"close(childSocketFD)");
  2055.                 close(childSocketFD);
  2056.                 return NO;
  2057.         }
  2058.        
  2059.         // Prevent SIGPIPE signals
  2060.        
  2061.         int nosigpipe = 1;
  2062.         setsockopt(childSocketFD, SOL_SOCKET, SO_NOSIGPIPE, &nosigpipe, sizeof(nosigpipe));
  2063.        
  2064.         // Notify delegate
  2065.        
  2066.         if (delegateQueue)
  2067.         {
  2068.                 __strong id<GCDAsyncSocketDelegate> theDelegate = delegate;
  2069.                
  2070.                 dispatch_async(delegateQueue, ^{ @autoreleasepool {
  2071.                        
  2072.                         // Query delegate for custom socket queue
  2073.                        
  2074.                         dispatch_queue_t childSocketQueue = NULL;
  2075.                        
  2076.                         if ([theDelegate respondsToSelector:@selector(newSocketQueueForConnectionFromAddress:onSocket:)])
  2077.                         {
  2078.                                 childSocketQueue = [theDelegate newSocketQueueForConnectionFromAddress:childSocketAddress
  2079.                                                                                               onSocket:self];
  2080.                         }
  2081.                        
  2082.                         // Create GCDAsyncSocket instance for accepted socket
  2083.                        
  2084.                         GCDAsyncSocket *acceptedSocket = [[[self class] alloc] initWithDelegate:theDelegate
  2085.                                                                       delegateQueue:self->delegateQueue
  2086.                                                                                                                                                 socketQueue:childSocketQueue];
  2087.                        
  2088.                         if (socketType == 0)
  2089.                                 acceptedSocket->socket4FD = childSocketFD;
  2090.                         else if (socketType == 1)
  2091.                                 acceptedSocket->socket6FD = childSocketFD;
  2092.                         else
  2093.                                 acceptedSocket->socketUN = childSocketFD;
  2094.                        
  2095.                         acceptedSocket->flags = (kSocketStarted | kConnected);
  2096.                        
  2097.                         // Setup read and write sources for accepted socket
  2098.                        
  2099.                         dispatch_async(acceptedSocket->socketQueue, ^{ @autoreleasepool {
  2100.                                
  2101.                                 [acceptedSocket setupReadAndWriteSourcesForNewlyConnectedSocket:childSocketFD];
  2102.                         }});
  2103.                        
  2104.                         // Notify delegate
  2105.                        
  2106.                         if ([theDelegate respondsToSelector:@selector(socket:didAcceptNewSocket:)])
  2107.                         {
  2108.                                 [theDelegate socket:self didAcceptNewSocket:acceptedSocket];
  2109.                         }
  2110.                        
  2111.                         // Release the socket queue returned from the delegate (it was retained by acceptedSocket)
  2112.                         #if !OS_OBJECT_USE_OBJC
  2113.                         if (childSocketQueue) dispatch_release(childSocketQueue);
  2114.                         #endif
  2115.                        
  2116.                         // The accepted socket should have been retained by the delegate.
  2117.                         // Otherwise it gets properly released when exiting the block.
  2118.                 }});
  2119.         }
  2120.        
  2121.         return YES;
  2122. }
  2123.  
  2124. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2125. #pragma mark Connecting
  2126. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2127.  
  2128. /**
  2129.  * This method runs through the various checks required prior to a connection attempt.
  2130.  * It is shared between the connectToHost and connectToAddress methods.
  2131.  *
  2132. **/
  2133. - (BOOL)preConnectWithInterface:(NSString *)interface error:(NSError **)errPtr
  2134. {
  2135.         NSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @"Must be dispatched on socketQueue");
  2136.        
  2137.         if (delegate == nil) // Must have delegate set
  2138.         {
  2139.                 if (errPtr)
  2140.                 {
  2141.                         NSString *msg = @"Attempting to connect without a delegate. Set a delegate first.";
  2142.                         *errPtr = [self badConfigError:msg];
  2143.                 }
  2144.                 return NO;
  2145.         }
  2146.        
  2147.         if (delegateQueue == NULL) // Must have delegate queue set
  2148.         {
  2149.                 if (errPtr)
  2150.                 {
  2151.                         NSString *msg = @"Attempting to connect without a delegate queue. Set a delegate queue first.";
  2152.                         *errPtr = [self badConfigError:msg];
  2153.                 }
  2154.                 return NO;
  2155.         }
  2156.        
  2157.         if (![self isDisconnected]) // Must be disconnected
  2158.         {
  2159.                 if (errPtr)
  2160.                 {
  2161.                         NSString *msg = @"Attempting to connect while connected or accepting connections. Disconnect first.";
  2162.                         *errPtr = [self badConfigError:msg];
  2163.                 }
  2164.                 return NO;
  2165.         }
  2166.        
  2167.         BOOL isIPv4Disabled = (config & kIPv4Disabled) ? YES : NO;
  2168.         BOOL isIPv6Disabled = (config & kIPv6Disabled) ? YES : NO;
  2169.        
  2170.         if (isIPv4Disabled && isIPv6Disabled) // Must have IPv4 or IPv6 enabled
  2171.         {
  2172.                 if (errPtr)
  2173.                 {
  2174.                         NSString *msg = @"Both IPv4 and IPv6 have been disabled. Must enable at least one protocol first.";
  2175.                         *errPtr = [self badConfigError:msg];
  2176.                 }
  2177.                 return NO;
  2178.         }
  2179.        
  2180.         if (interface)
  2181.         {
  2182.                 NSMutableData *interface4 = nil;
  2183.                 NSMutableData *interface6 = nil;
  2184.                
  2185.                 [self getInterfaceAddress4:&interface4 address6:&interface6 fromDescription:interface port:0];
  2186.                
  2187.                 if ((interface4 == nil) && (interface6 == nil))
  2188.                 {
  2189.                         if (errPtr)
  2190.                         {
  2191.                                 NSString *msg = @"Unknown interface. Specify valid interface by name (e.g. \"en1\") or IP address.";
  2192.                                 *errPtr = [self badParamError:msg];
  2193.                         }
  2194.                         return NO;
  2195.                 }
  2196.                
  2197.                 if (isIPv4Disabled && (interface6 == nil))
  2198.                 {
  2199.                         if (errPtr)
  2200.                         {
  2201.                                 NSString *msg = @"IPv4 has been disabled and specified interface doesn't support IPv6.";
  2202.                                 *errPtr = [self badParamError:msg];
  2203.                         }
  2204.                         return NO;
  2205.                 }
  2206.                
  2207.                 if (isIPv6Disabled && (interface4 == nil))
  2208.                 {
  2209.                         if (errPtr)
  2210.                         {
  2211.                                 NSString *msg = @"IPv6 has been disabled and specified interface doesn't support IPv4.";
  2212.                                 *errPtr = [self badParamError:msg];
  2213.                         }
  2214.                         return NO;
  2215.                 }
  2216.                
  2217.                 connectInterface4 = interface4;
  2218.                 connectInterface6 = interface6;
  2219.         }
  2220.        
  2221.         // Clear queues (spurious read/write requests post disconnect)
  2222.         [readQueue removeAllObjects];
  2223.         [writeQueue removeAllObjects];
  2224.        
  2225.         return YES;
  2226. }
  2227.  
  2228. - (BOOL)preConnectWithUrl:(NSURL *)url error:(NSError **)errPtr
  2229. {
  2230.         NSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @"Must be dispatched on socketQueue");
  2231.        
  2232.         if (delegate == nil) // Must have delegate set
  2233.         {
  2234.                 if (errPtr)
  2235.                 {
  2236.                         NSString *msg = @"Attempting to connect without a delegate. Set a delegate first.";
  2237.                         *errPtr = [self badConfigError:msg];
  2238.                 }
  2239.                 return NO;
  2240.         }
  2241.        
  2242.         if (delegateQueue == NULL) // Must have delegate queue set
  2243.         {
  2244.                 if (errPtr)
  2245.                 {
  2246.                         NSString *msg = @"Attempting to connect without a delegate queue. Set a delegate queue first.";
  2247.                         *errPtr = [self badConfigError:msg];
  2248.                 }
  2249.                 return NO;
  2250.         }
  2251.        
  2252.         if (![self isDisconnected]) // Must be disconnected
  2253.         {
  2254.                 if (errPtr)
  2255.                 {
  2256.                         NSString *msg = @"Attempting to connect while connected or accepting connections. Disconnect first.";
  2257.                         *errPtr = [self badConfigError:msg];
  2258.                 }
  2259.                 return NO;
  2260.         }
  2261.        
  2262.         NSData *interface = [self getInterfaceAddressFromUrl:url];
  2263.        
  2264.         if (interface == nil)
  2265.         {
  2266.                 if (errPtr)
  2267.                 {
  2268.                         NSString *msg = @"Unknown interface. Specify valid interface by name (e.g. \"en1\") or IP address.";
  2269.                         *errPtr = [self badParamError:msg];
  2270.                 }
  2271.                 return NO;
  2272.         }
  2273.        
  2274.         connectInterfaceUN = interface;
  2275.        
  2276.         // Clear queues (spurious read/write requests post disconnect)
  2277.         [readQueue removeAllObjects];
  2278.         [writeQueue removeAllObjects];
  2279.        
  2280.         return YES;
  2281. }
  2282.  
  2283. - (BOOL)connectToHost:(NSString*)host onPort:(uint16_t)port error:(NSError **)errPtr
  2284. {
  2285.         return [self connectToHost:host onPort:port withTimeout:-1 error:errPtr];
  2286. }
  2287.  
  2288. - (BOOL)connectToHost:(NSString *)host
  2289.                onPort:(uint16_t)port
  2290.           withTimeout:(NSTimeInterval)timeout
  2291.                 error:(NSError **)errPtr
  2292. {
  2293.         return [self connectToHost:host onPort:port viaInterface:nil withTimeout:timeout error:errPtr];
  2294. }
  2295.  
  2296. - (BOOL)connectToHost:(NSString *)inHost
  2297.                onPort:(uint16_t)port
  2298.          viaInterface:(NSString *)inInterface
  2299.           withTimeout:(NSTimeInterval)timeout
  2300.                 error:(NSError **)errPtr
  2301. {
  2302.         LogTrace();
  2303.        
  2304.         // Just in case immutable objects were passed
  2305.         NSString *host = [inHost copy];
  2306.         NSString *interface = [inInterface copy];
  2307.        
  2308.         __block BOOL result = NO;
  2309.         __block NSError *preConnectErr = nil;
  2310.        
  2311.         dispatch_block_t block = ^{ @autoreleasepool {
  2312.                
  2313.                 // Check for problems with host parameter
  2314.                
  2315.                 if ([host length] == 0)
  2316.                 {
  2317.                         NSString *msg = @"Invalid host parameter (nil or \"\"). Should be a domain name or IP address string.";
  2318.                         preConnectErr = [self badParamError:msg];
  2319.                        
  2320.                         return_from_block;
  2321.                 }
  2322.                
  2323.                 // Run through standard pre-connect checks
  2324.                
  2325.                 if (![self preConnectWithInterface:interface error:&preConnectErr])
  2326.                 {
  2327.                         return_from_block;
  2328.                 }
  2329.                
  2330.                 // We've made it past all the checks.
  2331.                 // It's time to start the connection process.
  2332.                
  2333.         self->flags |= kSocketStarted;
  2334.                
  2335.                 LogVerbose(@"Dispatching DNS lookup...");
  2336.                
  2337.                 // It's possible that the given host parameter is actually a NSMutableString.
  2338.                 // So we want to copy it now, within this block that will be executed synchronously.
  2339.                 // This way the asynchronous lookup block below doesn't have to worry about it changing.
  2340.                
  2341.                 NSString *hostCpy = [host copy];
  2342.                
  2343.         int aStateIndex = self->stateIndex;
  2344.                 __weak GCDAsyncSocket *weakSelf = self;
  2345.                
  2346.                 dispatch_queue_t globalConcurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
  2347.                 dispatch_async(globalConcurrentQueue, ^{ @autoreleasepool {
  2348.                 #pragma clang diagnostic push
  2349.                 #pragma clang diagnostic warning "-Wimplicit-retain-self"
  2350.                        
  2351.                         NSError *lookupErr = nil;
  2352.                         NSMutableArray *addresses = [[self class] lookupHost:hostCpy port:port error:&lookupErr];
  2353.                        
  2354.                         __strong GCDAsyncSocket *strongSelf = weakSelf;
  2355.                         if (strongSelf == nil) return_from_block;
  2356.                        
  2357.                         if (lookupErr)
  2358.                         {
  2359.                                 dispatch_async(strongSelf->socketQueue, ^{ @autoreleasepool {
  2360.                                        
  2361.                                         [strongSelf lookup:aStateIndex didFail:lookupErr];
  2362.                                 }});
  2363.                         }
  2364.                         else
  2365.                         {
  2366.                                 NSData *address4 = nil;
  2367.                                 NSData *address6 = nil;
  2368.                                
  2369.                                 for (NSData *address in addresses)
  2370.                                 {
  2371.                                         if (!address4 && [[self class] isIPv4Address:address])
  2372.                                         {
  2373.                                                 address4 = address;
  2374.                                         }
  2375.                                         else if (!address6 && [[self class] isIPv6Address:address])
  2376.                                         {
  2377.                                                 address6 = address;
  2378.                                         }
  2379.                                 }
  2380.                                
  2381.                                 dispatch_async(strongSelf->socketQueue, ^{ @autoreleasepool {
  2382.                                        
  2383.                                         [strongSelf lookup:aStateIndex didSucceedWithAddress4:address4 address6:address6];
  2384.                                 }});
  2385.                         }
  2386.                        
  2387.                 #pragma clang diagnostic pop
  2388.                 }});
  2389.                
  2390.                 [self startConnectTimeout:timeout];
  2391.                
  2392.                 result = YES;
  2393.         }};
  2394.        
  2395.         if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
  2396.                 block();
  2397.         else
  2398.                 dispatch_sync(socketQueue, block);
  2399.        
  2400.        
  2401.         if (errPtr) *errPtr = preConnectErr;
  2402.         return result;
  2403. }
  2404.  
  2405. - (BOOL)connectToAddress:(NSData *)remoteAddr error:(NSError **)errPtr
  2406. {
  2407.         return [self connectToAddress:remoteAddr viaInterface:nil withTimeout:-1 error:errPtr];
  2408. }
  2409.  
  2410. - (BOOL)connectToAddress:(NSData *)remoteAddr withTimeout:(NSTimeInterval)timeout error:(NSError **)errPtr
  2411. {
  2412.         return [self connectToAddress:remoteAddr viaInterface:nil withTimeout:timeout error:errPtr];
  2413. }
  2414.  
  2415. - (BOOL)connectToAddress:(NSData *)inRemoteAddr
  2416.             viaInterface:(NSString *)inInterface
  2417.              withTimeout:(NSTimeInterval)timeout
  2418.                    error:(NSError **)errPtr
  2419. {
  2420.         LogTrace();
  2421.        
  2422.         // Just in case immutable objects were passed
  2423.         NSData *remoteAddr = [inRemoteAddr copy];
  2424.         NSString *interface = [inInterface copy];
  2425.        
  2426.         __block BOOL result = NO;
  2427.         __block NSError *err = nil;
  2428.        
  2429.         dispatch_block_t block = ^{ @autoreleasepool {
  2430.                
  2431.                 // Check for problems with remoteAddr parameter
  2432.                
  2433.                 NSData *address4 = nil;
  2434.                 NSData *address6 = nil;
  2435.                
  2436.                 if ([remoteAddr length] >= sizeof(struct sockaddr))
  2437.                 {
  2438.                         const struct sockaddr *sockaddr = (const struct sockaddr *)[remoteAddr bytes];
  2439.                        
  2440.                         if (sockaddr->sa_family == AF_INET)
  2441.                         {
  2442.                                 if ([remoteAddr length] == sizeof(struct sockaddr_in))
  2443.                                 {
  2444.                                         address4 = remoteAddr;
  2445.                                 }
  2446.                         }
  2447.                         else if (sockaddr->sa_family == AF_INET6)
  2448.                         {
  2449.                                 if ([remoteAddr length] == sizeof(struct sockaddr_in6))
  2450.                                 {
  2451.                                         address6 = remoteAddr;
  2452.                                 }
  2453.                         }
  2454.                 }
  2455.                
  2456.                 if ((address4 == nil) && (address6 == nil))
  2457.                 {
  2458.                         NSString *msg = @"A valid IPv4 or IPv6 address was not given";
  2459.                         err = [self badParamError:msg];
  2460.                        
  2461.                         return_from_block;
  2462.                 }
  2463.                
  2464.         BOOL isIPv4Disabled = (self->config & kIPv4Disabled) ? YES : NO;
  2465.         BOOL isIPv6Disabled = (self->config & kIPv6Disabled) ? YES : NO;
  2466.                
  2467.                 if (isIPv4Disabled && (address4 != nil))
  2468.                 {
  2469.                         NSString *msg = @"IPv4 has been disabled and an IPv4 address was passed.";
  2470.                         err = [self badParamError:msg];
  2471.                        
  2472.                         return_from_block;
  2473.                 }
  2474.                
  2475.                 if (isIPv6Disabled && (address6 != nil))
  2476.                 {
  2477.                         NSString *msg = @"IPv6 has been disabled and an IPv6 address was passed.";
  2478.                         err = [self badParamError:msg];
  2479.                        
  2480.                         return_from_block;
  2481.                 }
  2482.                
  2483.                 // Run through standard pre-connect checks
  2484.                
  2485.                 if (![self preConnectWithInterface:interface error:&err])
  2486.                 {
  2487.                         return_from_block;
  2488.                 }
  2489.                
  2490.                 // We've made it past all the checks.
  2491.                 // It's time to start the connection process.
  2492.                
  2493.                 if (![self connectWithAddress4:address4 address6:address6 error:&err])
  2494.                 {
  2495.                         return_from_block;
  2496.                 }
  2497.                
  2498.         self->flags |= kSocketStarted;
  2499.                
  2500.                 [self startConnectTimeout:timeout];
  2501.                
  2502.                 result = YES;
  2503.         }};
  2504.        
  2505.         if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
  2506.                 block();
  2507.         else
  2508.                 dispatch_sync(socketQueue, block);
  2509.        
  2510.         if (result == NO)
  2511.         {
  2512.                 if (errPtr)
  2513.                         *errPtr = err;
  2514.         }
  2515.        
  2516.         return result;
  2517. }
  2518.  
  2519. - (BOOL)connectToUrl:(NSURL *)url withTimeout:(NSTimeInterval)timeout error:(NSError **)errPtr
  2520. {
  2521.         LogTrace();
  2522.        
  2523.         __block BOOL result = NO;
  2524.         __block NSError *err = nil;
  2525.        
  2526.         dispatch_block_t block = ^{ @autoreleasepool {
  2527.                
  2528.                 // Check for problems with host parameter
  2529.                
  2530.                 if ([url.path length] == 0)
  2531.                 {
  2532.                         NSString *msg = @"Invalid unix domain socket url.";
  2533.                         err = [self badParamError:msg];
  2534.                        
  2535.                         return_from_block;
  2536.                 }
  2537.                
  2538.                 // Run through standard pre-connect checks
  2539.                
  2540.                 if (![self preConnectWithUrl:url error:&err])
  2541.                 {
  2542.                         return_from_block;
  2543.                 }
  2544.                
  2545.                 // We've made it past all the checks.
  2546.                 // It's time to start the connection process.
  2547.                
  2548.         self->flags |= kSocketStarted;
  2549.                
  2550.                 // Start the normal connection process
  2551.                
  2552.                 NSError *connectError = nil;
  2553.         if (![self connectWithAddressUN:self->connectInterfaceUN error:&connectError])
  2554.                 {
  2555.                         [self closeWithError:connectError];
  2556.                        
  2557.                         return_from_block;
  2558.                 }
  2559.  
  2560.                 [self startConnectTimeout:timeout];
  2561.                
  2562.                 result = YES;
  2563.         }};
  2564.        
  2565.         if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
  2566.                 block();
  2567.         else
  2568.                 dispatch_sync(socketQueue, block);
  2569.        
  2570.         if (result == NO)
  2571.         {
  2572.                 if (errPtr)
  2573.                         *errPtr = err;
  2574.         }
  2575.        
  2576.         return result;
  2577. }
  2578.  
  2579. - (BOOL)connectToNetService:(NSNetService *)netService error:(NSError **)errPtr
  2580. {
  2581.         NSArray* addresses = [netService addresses];
  2582.         for (NSData* address in addresses)
  2583.         {
  2584.                 BOOL result = [self connectToAddress:address error:errPtr];
  2585.                 if (result)
  2586.                 {
  2587.                         return YES;
  2588.                 }
  2589.         }
  2590.        
  2591.         return NO;
  2592. }
  2593.  
  2594. - (void)lookup:(int)aStateIndex didSucceedWithAddress4:(NSData *)address4 address6:(NSData *)address6
  2595. {
  2596.         LogTrace();
  2597.        
  2598.         NSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @"Must be dispatched on socketQueue");
  2599.         NSAssert(address4 || address6, @"Expected at least one valid address");
  2600.        
  2601.         if (aStateIndex != stateIndex)
  2602.         {
  2603.                 LogInfo(@"Ignoring lookupDidSucceed, already disconnected");
  2604.                
  2605.                 // The connect operation has been cancelled.
  2606.                 // That is, socket was disconnected, or connection has already timed out.
  2607.                 return;
  2608.         }
  2609.        
  2610.         // Check for problems
  2611.        
  2612.         BOOL isIPv4Disabled = (config & kIPv4Disabled) ? YES : NO;
  2613.         BOOL isIPv6Disabled = (config & kIPv6Disabled) ? YES : NO;
  2614.        
  2615.         if (isIPv4Disabled && (address6 == nil))
  2616.         {
  2617.                 NSString *msg = @"IPv4 has been disabled and DNS lookup found no IPv6 address.";
  2618.                
  2619.                 [self closeWithError:[self otherError:msg]];
  2620.                 return;
  2621.         }
  2622.        
  2623.         if (isIPv6Disabled && (address4 == nil))
  2624.         {
  2625.                 NSString *msg = @"IPv6 has been disabled and DNS lookup found no IPv4 address.";
  2626.                
  2627.                 [self closeWithError:[self otherError:msg]];
  2628.                 return;
  2629.         }
  2630.        
  2631.         // Start the normal connection process
  2632.        
  2633.         NSError *err = nil;
  2634.         if (![self connectWithAddress4:address4 address6:address6 error:&err])
  2635.         {
  2636.                 [self closeWithError:err];
  2637.         }
  2638. }
  2639.  
  2640. /**
  2641.  * This method is called if the DNS lookup fails.
  2642.  * This method is executed on the socketQueue.
  2643.  *
  2644.  * Since the DNS lookup executed synchronously on a global concurrent queue,
  2645.  * the original connection request may have already been cancelled or timed-out by the time this method is invoked.
  2646.  * The lookupIndex tells us whether the lookup is still valid or not.
  2647. **/
  2648. - (void)lookup:(int)aStateIndex didFail:(NSError *)error
  2649. {
  2650.         LogTrace();
  2651.        
  2652.         NSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @"Must be dispatched on socketQueue");
  2653.        
  2654.        
  2655.         if (aStateIndex != stateIndex)
  2656.         {
  2657.                 LogInfo(@"Ignoring lookup:didFail: - already disconnected");
  2658.                
  2659.                 // The connect operation has been cancelled.
  2660.                 // That is, socket was disconnected, or connection has already timed out.
  2661.                 return;
  2662.         }
  2663.        
  2664.         [self endConnectTimeout];
  2665.         [self closeWithError:error];
  2666. }
  2667.  
  2668. - (BOOL)bindSocket:(int)socketFD toInterface:(NSData *)connectInterface error:(NSError **)errPtr
  2669. {
  2670.     // Bind the socket to the desired interface (if needed)
  2671.    
  2672.     if (connectInterface)
  2673.     {
  2674.         LogVerbose(@"Binding socket...");
  2675.        
  2676.         if ([[self class] portFromAddress:connectInterface] > 0)
  2677.         {
  2678.             // Since we're going to be binding to a specific port,
  2679.             // we should turn on reuseaddr to allow us to override sockets in time_wait.
  2680.            
  2681.             int reuseOn = 1;
  2682.             setsockopt(socketFD, SOL_SOCKET, SO_REUSEADDR, &reuseOn, sizeof(reuseOn));
  2683.         }
  2684.        
  2685.         const struct sockaddr *interfaceAddr = (const struct sockaddr *)[connectInterface bytes];
  2686.        
  2687.         int result = bind(socketFD, interfaceAddr, (socklen_t)[connectInterface length]);
  2688.         if (result != 0)
  2689.         {
  2690.             if (errPtr)
  2691.                 *errPtr = [self errorWithErrno:errno reason:@"Error in bind() function"];
  2692.            
  2693.             return NO;
  2694.         }
  2695.     }
  2696.    
  2697.     return YES;
  2698. }
  2699.  
  2700. - (int)createSocket:(int)family connectInterface:(NSData *)connectInterface errPtr:(NSError **)errPtr
  2701. {
  2702.     int socketFD = socket(family, SOCK_STREAM, 0);
  2703.    
  2704.     if (socketFD == SOCKET_NULL)
  2705.     {
  2706.         if (errPtr)
  2707.             *errPtr = [self errorWithErrno:errno reason:@"Error in socket() function"];
  2708.        
  2709.         return socketFD;
  2710.     }
  2711.    
  2712.     if (![self bindSocket:socketFD toInterface:connectInterface error:errPtr])
  2713.     {
  2714.         [self closeSocket:socketFD];
  2715.        
  2716.         return SOCKET_NULL;
  2717.     }
  2718.    
  2719.     // Prevent SIGPIPE signals
  2720.    
  2721.     int nosigpipe = 1;
  2722.     setsockopt(socketFD, SOL_SOCKET, SO_NOSIGPIPE, &nosigpipe, sizeof(nosigpipe));
  2723.    
  2724.     return socketFD;
  2725. }
  2726.  
  2727. - (void)connectSocket:(int)socketFD address:(NSData *)address stateIndex:(int)aStateIndex
  2728. {
  2729.     // If there already is a socket connected, we close socketFD and return
  2730.     if (self.isConnected)
  2731.     {
  2732.         [self closeSocket:socketFD];
  2733.         return;
  2734.     }
  2735.    
  2736.     // Start the connection process in a background queue
  2737.    
  2738.     __weak GCDAsyncSocket *weakSelf = self;
  2739.    
  2740.     dispatch_queue_t globalConcurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
  2741.     dispatch_async(globalConcurrentQueue, ^{
  2742. #pragma clang diagnostic push
  2743. #pragma clang diagnostic warning "-Wimplicit-retain-self"
  2744.        
  2745.         int result = connect(socketFD, (const struct sockaddr *)[address bytes], (socklen_t)[address length]);
  2746.         int err = errno;
  2747.        
  2748.         __strong GCDAsyncSocket *strongSelf = weakSelf;
  2749.         if (strongSelf == nil) return_from_block;
  2750.        
  2751.         dispatch_async(strongSelf->socketQueue, ^{ @autoreleasepool {
  2752.            
  2753.             if (strongSelf.isConnected)
  2754.             {
  2755.                 [strongSelf closeSocket:socketFD];
  2756.                 return_from_block;
  2757.             }
  2758.            
  2759.             if (result == 0)
  2760.             {
  2761.                 [self closeUnusedSocket:socketFD];
  2762.                
  2763.                 [strongSelf didConnect:aStateIndex];
  2764.             }
  2765.             else
  2766.             {
  2767.                 [strongSelf closeSocket:socketFD];
  2768.                
  2769.                 // If there are no more sockets trying to connect, we inform the error to the delegate
  2770.                 if (strongSelf.socket4FD == SOCKET_NULL && strongSelf.socket6FD == SOCKET_NULL)
  2771.                 {
  2772.                     NSError *error = [strongSelf errorWithErrno:err reason:@"Error in connect() function"];
  2773.                     [strongSelf didNotConnect:aStateIndex error:error];
  2774.                 }
  2775.             }
  2776.         }});
  2777.        
  2778. #pragma clang diagnostic pop
  2779.     });
  2780.    
  2781.     LogVerbose(@"Connecting...");
  2782. }
  2783.  
  2784. - (void)closeSocket:(int)socketFD
  2785. {
  2786.     if (socketFD != SOCKET_NULL &&
  2787.         (socketFD == socket6FD || socketFD == socket4FD))
  2788.     {
  2789.         close(socketFD);
  2790.        
  2791.         if (socketFD == socket4FD)
  2792.         {
  2793.             LogVerbose(@"close(socket4FD)");
  2794.             socket4FD = SOCKET_NULL;
  2795.         }
  2796.         else if (socketFD == socket6FD)
  2797.         {
  2798.             LogVerbose(@"close(socket6FD)");
  2799.             socket6FD = SOCKET_NULL;
  2800.         }
  2801.     }
  2802. }
  2803.  
  2804. - (void)closeUnusedSocket:(int)usedSocketFD
  2805. {
  2806.     if (usedSocketFD != socket4FD)
  2807.     {
  2808.         [self closeSocket:socket4FD];
  2809.     }
  2810.     else if (usedSocketFD != socket6FD)
  2811.     {
  2812.         [self closeSocket:socket6FD];
  2813.     }
  2814. }
  2815.  
  2816. - (BOOL)connectWithAddress4:(NSData *)address4 address6:(NSData *)address6 error:(NSError **)errPtr
  2817. {
  2818.         LogTrace();
  2819.        
  2820.         NSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @"Must be dispatched on socketQueue");
  2821.        
  2822.         LogVerbose(@"IPv4: %@:%hu", [[self class] hostFromAddress:address4], [[self class] portFromAddress:address4]);
  2823.         LogVerbose(@"IPv6: %@:%hu", [[self class] hostFromAddress:address6], [[self class] portFromAddress:address6]);
  2824.        
  2825.         // Determine socket type
  2826.        
  2827.         BOOL preferIPv6 = (config & kPreferIPv6) ? YES : NO;
  2828.        
  2829.         // Create and bind the sockets
  2830.    
  2831.     if (address4)
  2832.     {
  2833.         LogVerbose(@"Creating IPv4 socket");
  2834.        
  2835.         socket4FD = [self createSocket:AF_INET connectInterface:connectInterface4 errPtr:errPtr];
  2836.     }
  2837.    
  2838.     if (address6)
  2839.     {
  2840.         LogVerbose(@"Creating IPv6 socket");
  2841.        
  2842.         socket6FD = [self createSocket:AF_INET6 connectInterface:connectInterface6 errPtr:errPtr];
  2843.     }
  2844.    
  2845.     if (socket4FD == SOCKET_NULL && socket6FD == SOCKET_NULL)
  2846.     {
  2847.         return NO;
  2848.     }
  2849.        
  2850.         int socketFD, alternateSocketFD;
  2851.         NSData *address, *alternateAddress;
  2852.        
  2853.     if ((preferIPv6 && socket6FD != SOCKET_NULL) || socket4FD == SOCKET_NULL)
  2854.     {
  2855.         socketFD = socket6FD;
  2856.         alternateSocketFD = socket4FD;
  2857.         address = address6;
  2858.         alternateAddress = address4;
  2859.     }
  2860.     else
  2861.     {
  2862.         socketFD = socket4FD;
  2863.         alternateSocketFD = socket6FD;
  2864.         address = address4;
  2865.         alternateAddress = address6;
  2866.     }
  2867.  
  2868.     int aStateIndex = stateIndex;
  2869.    
  2870.     [self connectSocket:socketFD address:address stateIndex:aStateIndex];
  2871.    
  2872.     if (alternateAddress)
  2873.     {
  2874.         dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(alternateAddressDelay * NSEC_PER_SEC)), socketQueue, ^{
  2875.             [self connectSocket:alternateSocketFD address:alternateAddress stateIndex:aStateIndex];
  2876.         });
  2877.     }
  2878.        
  2879.         return YES;
  2880. }
  2881.  
  2882. - (BOOL)connectWithAddressUN:(NSData *)address error:(NSError **)errPtr
  2883. {
  2884.         LogTrace();
  2885.        
  2886.         NSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @"Must be dispatched on socketQueue");
  2887.        
  2888.         // Create the socket
  2889.        
  2890.         int socketFD;
  2891.        
  2892.         LogVerbose(@"Creating unix domain socket");
  2893.        
  2894.         socketUN = socket(AF_UNIX, SOCK_STREAM, 0);
  2895.        
  2896.         socketFD = socketUN;
  2897.        
  2898.         if (socketFD == SOCKET_NULL)
  2899.         {
  2900.                 if (errPtr)
  2901.                         *errPtr = [self errorWithErrno:errno reason:@"Error in socket() function"];
  2902.                
  2903.                 return NO;
  2904.         }
  2905.        
  2906.         // Bind the socket to the desired interface (if needed)
  2907.        
  2908.         LogVerbose(@"Binding socket...");
  2909.        
  2910.         int reuseOn = 1;
  2911.         setsockopt(socketFD, SOL_SOCKET, SO_REUSEADDR, &reuseOn, sizeof(reuseOn));
  2912.  
  2913. //      const struct sockaddr *interfaceAddr = (const struct sockaddr *)[address bytes];
  2914. //     
  2915. //      int result = bind(socketFD, interfaceAddr, (socklen_t)[address length]);
  2916. //      if (result != 0)
  2917. //      {
  2918. //              if (errPtr)
  2919. //                      *errPtr = [self errnoErrorWithReason:@"Error in bind() function"];
  2920. //             
  2921. //              return NO;
  2922. //      }
  2923.        
  2924.         // Prevent SIGPIPE signals
  2925.        
  2926.         int nosigpipe = 1;
  2927.         setsockopt(socketFD, SOL_SOCKET, SO_NOSIGPIPE, &nosigpipe, sizeof(nosigpipe));
  2928.        
  2929.         // Start the connection process in a background queue
  2930.        
  2931.         int aStateIndex = stateIndex;
  2932.        
  2933.         dispatch_queue_t globalConcurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
  2934.         dispatch_async(globalConcurrentQueue, ^{
  2935.                
  2936.                 const struct sockaddr *addr = (const struct sockaddr *)[address bytes];
  2937.                 int result = connect(socketFD, addr, addr->sa_len);
  2938.                 if (result == 0)
  2939.                 {
  2940.             dispatch_async(self->socketQueue, ^{ @autoreleasepool {
  2941.                                
  2942.                                 [self didConnect:aStateIndex];
  2943.                         }});
  2944.                 }
  2945.                 else
  2946.                 {
  2947.                         // TODO: Bad file descriptor
  2948.                         perror("connect");
  2949.                         NSError *error = [self errorWithErrno:errno reason:@"Error in connect() function"];
  2950.                        
  2951.             dispatch_async(self->socketQueue, ^{ @autoreleasepool {
  2952.                                
  2953.                                 [self didNotConnect:aStateIndex error:error];
  2954.                         }});
  2955.                 }
  2956.         });
  2957.        
  2958.         LogVerbose(@"Connecting...");
  2959.        
  2960.         return YES;
  2961. }
  2962.  
  2963. - (void)didConnect:(int)aStateIndex
  2964. {
  2965.         LogTrace();
  2966.        
  2967.         NSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @"Must be dispatched on socketQueue");
  2968.        
  2969.        
  2970.         if (aStateIndex != stateIndex)
  2971.         {
  2972.                 LogInfo(@"Ignoring didConnect, already disconnected");
  2973.                
  2974.                 // The connect operation has been cancelled.
  2975.                 // That is, socket was disconnected, or connection has already timed out.
  2976.                 return;
  2977.         }
  2978.        
  2979.         flags |= kConnected;
  2980.        
  2981.         [self endConnectTimeout];
  2982.        
  2983.         #if TARGET_OS_IPHONE
  2984.         // The endConnectTimeout method executed above incremented the stateIndex.
  2985.         aStateIndex = stateIndex;
  2986.         #endif
  2987.        
  2988.         // Setup read/write streams (as workaround for specific shortcomings in the iOS platform)
  2989.         //
  2990.         // Note:
  2991.         // There may be configuration options that must be set by the delegate before opening the streams.
  2992.         // The primary example is the kCFStreamNetworkServiceTypeVoIP flag, which only works on an unopened stream.
  2993.         //
  2994.         // Thus we wait until after the socket:didConnectToHost:port: delegate method has completed.
  2995.         // This gives the delegate time to properly configure the streams if needed.
  2996.        
  2997.         dispatch_block_t SetupStreamsPart1 = ^{
  2998.                 #if TARGET_OS_IPHONE
  2999.                
  3000.                 if (![self createReadAndWriteStream])
  3001.                 {
  3002.                         [self closeWithError:[self otherError:@"Error creating CFStreams"]];
  3003.                         return;
  3004.                 }
  3005.                
  3006.                 if (![self registerForStreamCallbacksIncludingReadWrite:NO])
  3007.                 {
  3008.                         [self closeWithError:[self otherError:@"Error in CFStreamSetClient"]];
  3009.                         return;
  3010.                 }
  3011.                
  3012.                 #endif
  3013.         };
  3014.         dispatch_block_t SetupStreamsPart2 = ^{
  3015.                 #if TARGET_OS_IPHONE
  3016.                
  3017.         if (aStateIndex != self->stateIndex)
  3018.                 {
  3019.                         // The socket has been disconnected.
  3020.                         return;
  3021.                 }
  3022.                
  3023.                 if (![self addStreamsToRunLoop])
  3024.                 {
  3025.                         [self closeWithError:[self otherError:@"Error in CFStreamScheduleWithRunLoop"]];
  3026.                         return;
  3027.                 }
  3028.                
  3029.                 if (![self openStreams])
  3030.                 {
  3031.                         [self closeWithError:[self otherError:@"Error creating CFStreams"]];
  3032.                         return;
  3033.                 }
  3034.                
  3035.                 #endif
  3036.         };
  3037.        
  3038.         // Notify delegate
  3039.        
  3040.         NSString *host = [self connectedHost];
  3041.         uint16_t port = [self connectedPort];
  3042.         NSURL *url = [self connectedUrl];
  3043.        
  3044.         __strong id<GCDAsyncSocketDelegate> theDelegate = delegate;
  3045.  
  3046.         if (delegateQueue && host != nil && [theDelegate respondsToSelector:@selector(socket:didConnectToHost:port:)])
  3047.         {
  3048.                 SetupStreamsPart1();
  3049.                
  3050.                 dispatch_async(delegateQueue, ^{ @autoreleasepool {
  3051.                        
  3052.                         [theDelegate socket:self didConnectToHost:host port:port];
  3053.                        
  3054.             dispatch_async(self->socketQueue, ^{ @autoreleasepool {
  3055.                                
  3056.                                 SetupStreamsPart2();
  3057.                         }});
  3058.                 }});
  3059.         }
  3060.         else if (delegateQueue && url != nil && [theDelegate respondsToSelector:@selector(socket:didConnectToUrl:)])
  3061.         {
  3062.                 SetupStreamsPart1();
  3063.                
  3064.                 dispatch_async(delegateQueue, ^{ @autoreleasepool {
  3065.                        
  3066.                         [theDelegate socket:self didConnectToUrl:url];
  3067.                        
  3068.             dispatch_async(self->socketQueue, ^{ @autoreleasepool {
  3069.                                
  3070.                                 SetupStreamsPart2();
  3071.                         }});
  3072.                 }});
  3073.         }
  3074.         else
  3075.         {
  3076.                 SetupStreamsPart1();
  3077.                 SetupStreamsPart2();
  3078.         }
  3079.                
  3080.         // Get the connected socket
  3081.        
  3082.         int socketFD = (socket4FD != SOCKET_NULL) ? socket4FD : (socket6FD != SOCKET_NULL) ? socket6FD : socketUN;
  3083.        
  3084.         // Enable non-blocking IO on the socket
  3085.        
  3086.         int result = fcntl(socketFD, F_SETFL, O_NONBLOCK);
  3087.         if (result == -1)
  3088.         {
  3089.                 NSString *errMsg = @"Error enabling non-blocking IO on socket (fcntl)";
  3090.                 [self closeWithError:[self otherError:errMsg]];
  3091.                
  3092.                 return;
  3093.         }
  3094.        
  3095.         // Setup our read/write sources
  3096.        
  3097.         [self setupReadAndWriteSourcesForNewlyConnectedSocket:socketFD];
  3098.        
  3099.         // Dequeue any pending read/write requests
  3100.        
  3101.         [self maybeDequeueRead];
  3102.         [self maybeDequeueWrite];
  3103. }
  3104.  
  3105. - (void)didNotConnect:(int)aStateIndex error:(NSError *)error
  3106. {
  3107.         LogTrace();
  3108.        
  3109.         NSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @"Must be dispatched on socketQueue");
  3110.        
  3111.        
  3112.         if (aStateIndex != stateIndex)
  3113.         {
  3114.                 LogInfo(@"Ignoring didNotConnect, already disconnected");
  3115.                
  3116.                 // The connect operation has been cancelled.
  3117.                 // That is, socket was disconnected, or connection has already timed out.
  3118.                 return;
  3119.         }
  3120.        
  3121.         [self closeWithError:error];
  3122. }
  3123.  
  3124. - (void)startConnectTimeout:(NSTimeInterval)timeout
  3125. {
  3126.         if (timeout >= 0.0)
  3127.         {
  3128.                 connectTimer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, socketQueue);
  3129.                
  3130.                 __weak GCDAsyncSocket *weakSelf = self;
  3131.                
  3132.                 dispatch_source_set_event_handler(connectTimer, ^{ @autoreleasepool {
  3133.                 #pragma clang diagnostic push
  3134.                 #pragma clang diagnostic warning "-Wimplicit-retain-self"
  3135.                
  3136.                         __strong GCDAsyncSocket *strongSelf = weakSelf;
  3137.                         if (strongSelf == nil) return_from_block;
  3138.                        
  3139.                         [strongSelf doConnectTimeout];
  3140.                        
  3141.                 #pragma clang diagnostic pop
  3142.                 }});
  3143.                
  3144.                 #if !OS_OBJECT_USE_OBJC
  3145.                 dispatch_source_t theConnectTimer = connectTimer;
  3146.                 dispatch_source_set_cancel_handler(connectTimer, ^{
  3147.                 #pragma clang diagnostic push
  3148.                 #pragma clang diagnostic warning "-Wimplicit-retain-self"
  3149.                        
  3150.                         LogVerbose(@"dispatch_release(connectTimer)");
  3151.                         dispatch_release(theConnectTimer);
  3152.                        
  3153.                 #pragma clang diagnostic pop
  3154.                 });
  3155.                 #endif
  3156.                
  3157.                 dispatch_time_t tt = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(timeout * NSEC_PER_SEC));
  3158.                 dispatch_source_set_timer(connectTimer, tt, DISPATCH_TIME_FOREVER, 0);
  3159.                
  3160.                 dispatch_resume(connectTimer);
  3161.         }
  3162. }
  3163.  
  3164. - (void)endConnectTimeout
  3165. {
  3166.         LogTrace();
  3167.        
  3168.         if (connectTimer)
  3169.         {
  3170.                 dispatch_source_cancel(connectTimer);
  3171.                 connectTimer = NULL;
  3172.         }
  3173.        
  3174.         // Increment stateIndex.
  3175.         // This will prevent us from processing results from any related background asynchronous operations.
  3176.         //
  3177.         // Note: This should be called from close method even if connectTimer is NULL.
  3178.         // This is because one might disconnect a socket prior to a successful connection which had no timeout.
  3179.        
  3180.         stateIndex++;
  3181.        
  3182.         if (connectInterface4)
  3183.         {
  3184.                 connectInterface4 = nil;
  3185.         }
  3186.         if (connectInterface6)
  3187.         {
  3188.                 connectInterface6 = nil;
  3189.         }
  3190. }
  3191.  
  3192. - (void)doConnectTimeout
  3193. {
  3194.         LogTrace();
  3195.        
  3196.         [self endConnectTimeout];
  3197.         [self closeWithError:[self connectTimeoutError]];
  3198. }
  3199.  
  3200. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3201. #pragma mark Disconnecting
  3202. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3203.  
  3204. - (void)closeWithError:(NSError *)error
  3205. {
  3206.         LogTrace();
  3207.         NSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @"Must be dispatched on socketQueue");
  3208.        
  3209.         [self endConnectTimeout];
  3210.        
  3211.         if (currentRead != nil)  [self endCurrentRead];
  3212.         if (currentWrite != nil) [self endCurrentWrite];
  3213.        
  3214.         [readQueue removeAllObjects];
  3215.         [writeQueue removeAllObjects];
  3216.        
  3217.         [preBuffer reset];
  3218.        
  3219.         #if TARGET_OS_IPHONE
  3220.         {
  3221.                 if (readStream || writeStream)
  3222.                 {
  3223.                         [self removeStreamsFromRunLoop];
  3224.                        
  3225.                         if (readStream)
  3226.                         {
  3227.                                 CFReadStreamSetClient(readStream, kCFStreamEventNone, NULL, NULL);
  3228.                                 CFReadStreamClose(readStream);
  3229.                                 CFRelease(readStream);
  3230.                                 readStream = NULL;
  3231.                         }
  3232.                         if (writeStream)
  3233.                         {
  3234.                                 CFWriteStreamSetClient(writeStream, kCFStreamEventNone, NULL, NULL);
  3235.                                 CFWriteStreamClose(writeStream);
  3236.                                 CFRelease(writeStream);
  3237.                                 writeStream = NULL;
  3238.                         }
  3239.                 }
  3240.         }
  3241.         #endif
  3242.        
  3243.         [sslPreBuffer reset];
  3244.         sslErrCode = lastSSLHandshakeError = noErr;
  3245.        
  3246.         if (sslContext)
  3247.         {
  3248.                 // Getting a linker error here about the SSLx() functions?
  3249.                 // You need to add the Security Framework to your application.
  3250.                
  3251.                 SSLClose(sslContext);
  3252.                
  3253.                 #if TARGET_OS_IPHONE || (__MAC_OS_X_VERSION_MIN_REQUIRED >= 1080)
  3254.                 CFRelease(sslContext);
  3255.                 #else
  3256.                 SSLDisposeContext(sslContext);
  3257.                 #endif
  3258.                
  3259.                 sslContext = NULL;
  3260.         }
  3261.        
  3262.         // For some crazy reason (in my opinion), cancelling a dispatch source doesn't
  3263.         // invoke the cancel handler if the dispatch source is paused.
  3264.         // So we have to unpause the source if needed.
  3265.         // This allows the cancel handler to be run, which in turn releases the source and closes the socket.
  3266.        
  3267.         if (!accept4Source && !accept6Source && !acceptUNSource && !readSource && !writeSource)
  3268.         {
  3269.                 LogVerbose(@"manually closing close");
  3270.  
  3271.                 if (socket4FD != SOCKET_NULL)
  3272.                 {
  3273.                         LogVerbose(@"close(socket4FD)");
  3274.                         close(socket4FD);
  3275.                         socket4FD = SOCKET_NULL;
  3276.                 }
  3277.  
  3278.                 if (socket6FD != SOCKET_NULL)
  3279.                 {
  3280.                         LogVerbose(@"close(socket6FD)");
  3281.                         close(socket6FD);
  3282.                         socket6FD = SOCKET_NULL;
  3283.                 }
  3284.                
  3285.                 if (socketUN != SOCKET_NULL)
  3286.                 {
  3287.                         LogVerbose(@"close(socketUN)");
  3288.                         close(socketUN);
  3289.                         socketUN = SOCKET_NULL;
  3290.                         unlink(socketUrl.path.fileSystemRepresentation);
  3291.                         socketUrl = nil;
  3292.                 }
  3293.         }
  3294.         else
  3295.         {
  3296.                 if (accept4Source)
  3297.                 {
  3298.                         LogVerbose(@"dispatch_source_cancel(accept4Source)");
  3299.                         dispatch_source_cancel(accept4Source);
  3300.                        
  3301.                         // We never suspend accept4Source
  3302.                        
  3303.                         accept4Source = NULL;
  3304.                 }
  3305.                
  3306.                 if (accept6Source)
  3307.                 {
  3308.                         LogVerbose(@"dispatch_source_cancel(accept6Source)");
  3309.                         dispatch_source_cancel(accept6Source);
  3310.                        
  3311.                         // We never suspend accept6Source
  3312.                        
  3313.                         accept6Source = NULL;
  3314.                 }
  3315.                
  3316.                 if (acceptUNSource)
  3317.                 {
  3318.                         LogVerbose(@"dispatch_source_cancel(acceptUNSource)");
  3319.                         dispatch_source_cancel(acceptUNSource);
  3320.                        
  3321.                         // We never suspend acceptUNSource
  3322.                        
  3323.                         acceptUNSource = NULL;
  3324.                 }
  3325.        
  3326.                 if (readSource)
  3327.                 {
  3328.                         LogVerbose(@"dispatch_source_cancel(readSource)");
  3329.                         dispatch_source_cancel(readSource);
  3330.                        
  3331.                         [self resumeReadSource];
  3332.                        
  3333.                         readSource = NULL;
  3334.                 }
  3335.                
  3336.                 if (writeSource)
  3337.                 {
  3338.                         LogVerbose(@"dispatch_source_cancel(writeSource)");
  3339.                         dispatch_source_cancel(writeSource);
  3340.                        
  3341.                         [self resumeWriteSource];
  3342.                        
  3343.                         writeSource = NULL;
  3344.                 }
  3345.                
  3346.                 // The sockets will be closed by the cancel handlers of the corresponding source
  3347.                
  3348.                 socket4FD = SOCKET_NULL;
  3349.                 socket6FD = SOCKET_NULL;
  3350.                 socketUN = SOCKET_NULL;
  3351.         }
  3352.        
  3353.         // If the client has passed the connect/accept method, then the connection has at least begun.
  3354.         // Notify delegate that it is now ending.
  3355.         BOOL shouldCallDelegate = (flags & kSocketStarted) ? YES : NO;
  3356.         BOOL isDeallocating = (flags & kDealloc) ? YES : NO;
  3357.        
  3358.         // Clear stored socket info and all flags (config remains as is)
  3359.         socketFDBytesAvailable = 0;
  3360.         flags = 0;
  3361.         sslWriteCachedLength = 0;
  3362.        
  3363.         if (shouldCallDelegate)
  3364.         {
  3365.                 __strong id<GCDAsyncSocketDelegate> theDelegate = delegate;
  3366.                 __strong id theSelf = isDeallocating ? nil : self;
  3367.                
  3368.                 if (delegateQueue && [theDelegate respondsToSelector: @selector(socketDidDisconnect:withError:)])
  3369.                 {
  3370.                         dispatch_async(delegateQueue, ^{ @autoreleasepool {
  3371.                                
  3372.                                 [theDelegate socketDidDisconnect:theSelf withError:error];
  3373.                         }});
  3374.                 }      
  3375.         }
  3376. }
  3377.  
  3378. - (void)disconnect
  3379. {
  3380.         dispatch_block_t block = ^{ @autoreleasepool {
  3381.                
  3382.         if (self->flags & kSocketStarted)
  3383.                 {
  3384.                         [self closeWithError:nil];
  3385.                 }
  3386.         }};
  3387.        
  3388.         // Synchronous disconnection, as documented in the header file
  3389.        
  3390.         if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
  3391.                 block();
  3392.         else
  3393.                 dispatch_sync(socketQueue, block);
  3394. }
  3395.  
  3396. - (void)disconnectAfterReading
  3397. {
  3398.         dispatch_async(socketQueue, ^{ @autoreleasepool {
  3399.                
  3400.         if (self->flags & kSocketStarted)
  3401.                 {
  3402.             self->flags |= (kForbidReadsWrites | kDisconnectAfterReads);
  3403.                         [self maybeClose];
  3404.                 }
  3405.         }});
  3406. }
  3407.  
  3408. - (void)disconnectAfterWriting
  3409. {
  3410.         dispatch_async(socketQueue, ^{ @autoreleasepool {
  3411.                
  3412.         if (self->flags & kSocketStarted)
  3413.                 {
  3414.             self->flags |= (kForbidReadsWrites | kDisconnectAfterWrites);
  3415.                         [self maybeClose];
  3416.                 }
  3417.         }});
  3418. }
  3419.  
  3420. - (void)disconnectAfterReadingAndWriting
  3421. {
  3422.         dispatch_async(socketQueue, ^{ @autoreleasepool {
  3423.                
  3424.         if (self->flags & kSocketStarted)
  3425.                 {
  3426.             self->flags |= (kForbidReadsWrites | kDisconnectAfterReads | kDisconnectAfterWrites);
  3427.                         [self maybeClose];
  3428.                 }
  3429.         }});
  3430. }
  3431.  
  3432. /**
  3433.  * Closes the socket if possible.
  3434.  * That is, if all writes have completed, and we're set to disconnect after writing,
  3435.  * or if all reads have completed, and we're set to disconnect after reading.
  3436. **/
  3437. - (void)maybeClose
  3438. {
  3439.         NSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @"Must be dispatched on socketQueue");
  3440.        
  3441.         BOOL shouldClose = NO;
  3442.        
  3443.         if (flags & kDisconnectAfterReads)
  3444.         {
  3445.                 if (([readQueue count] == 0) && (currentRead == nil))
  3446.                 {
  3447.                         if (flags & kDisconnectAfterWrites)
  3448.                         {
  3449.                                 if (([writeQueue count] == 0) && (currentWrite == nil))
  3450.                                 {
  3451.                                         shouldClose = YES;
  3452.                                 }
  3453.                         }
  3454.                         else
  3455.                         {
  3456.                                 shouldClose = YES;
  3457.                         }
  3458.                 }
  3459.         }
  3460.         else if (flags & kDisconnectAfterWrites)
  3461.         {
  3462.                 if (([writeQueue count] == 0) && (currentWrite == nil))
  3463.                 {
  3464.                         shouldClose = YES;
  3465.                 }
  3466.         }
  3467.        
  3468.         if (shouldClose)
  3469.         {
  3470.                 [self closeWithError:nil];
  3471.         }
  3472. }
  3473.  
  3474. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3475. #pragma mark Errors
  3476. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3477.  
  3478. - (NSError *)badConfigError:(NSString *)errMsg
  3479. {
  3480.         NSDictionary *userInfo = @{NSLocalizedDescriptionKey : errMsg};
  3481.        
  3482.         return [NSError errorWithDomain:GCDAsyncSocketErrorDomain code:GCDAsyncSocketBadConfigError userInfo:userInfo];
  3483. }
  3484.  
  3485. - (NSError *)badParamError:(NSString *)errMsg
  3486. {
  3487.         NSDictionary *userInfo = @{NSLocalizedDescriptionKey : errMsg};
  3488.        
  3489.         return [NSError errorWithDomain:GCDAsyncSocketErrorDomain code:GCDAsyncSocketBadParamError userInfo:userInfo];
  3490. }
  3491.  
  3492. + (NSError *)gaiError:(int)gai_error
  3493. {
  3494.         NSString *errMsg = [NSString stringWithCString:gai_strerror(gai_error) encoding:NSASCIIStringEncoding];
  3495.         NSDictionary *userInfo = @{NSLocalizedDescriptionKey : errMsg};
  3496.        
  3497.         return [NSError errorWithDomain:@"kCFStreamErrorDomainNetDB" code:gai_error userInfo:userInfo];
  3498. }
  3499.  
  3500. - (NSError *)errorWithErrno:(int)err reason:(NSString *)reason
  3501. {
  3502.         NSString *errMsg = [NSString stringWithUTF8String:strerror(err)];
  3503.         NSDictionary *userInfo = @{NSLocalizedDescriptionKey : errMsg,
  3504.                                                            NSLocalizedFailureReasonErrorKey : reason};
  3505.        
  3506.         return [NSError errorWithDomain:NSPOSIXErrorDomain code:err userInfo:userInfo];
  3507. }
  3508.  
  3509. - (NSError *)errnoError
  3510. {
  3511.         NSString *errMsg = [NSString stringWithUTF8String:strerror(errno)];
  3512.         NSDictionary *userInfo = @{NSLocalizedDescriptionKey : errMsg};
  3513.        
  3514.         return [NSError errorWithDomain:NSPOSIXErrorDomain code:errno userInfo:userInfo];
  3515. }
  3516.  
  3517. - (NSError *)sslError:(OSStatus)ssl_error
  3518. {
  3519.         NSString *msg = @"Error code definition can be found in Apple's SecureTransport.h";
  3520.         NSDictionary *userInfo = @{NSLocalizedRecoverySuggestionErrorKey : msg};
  3521.        
  3522.         return [NSError errorWithDomain:@"kCFStreamErrorDomainSSL" code:ssl_error userInfo:userInfo];
  3523. }
  3524.  
  3525. - (NSError *)connectTimeoutError
  3526. {
  3527.         NSString *errMsg = NSLocalizedStringWithDefaultValue(@"GCDAsyncSocketConnectTimeoutError",
  3528.                                                              @"GCDAsyncSocket", [NSBundle mainBundle],
  3529.                                                              @"Attempt to connect to host timed out", nil);
  3530.        
  3531.         NSDictionary *userInfo = @{NSLocalizedDescriptionKey : errMsg};
  3532.        
  3533.         return [NSError errorWithDomain:GCDAsyncSocketErrorDomain code:GCDAsyncSocketConnectTimeoutError userInfo:userInfo];
  3534. }
  3535.  
  3536. /**
  3537.  * Returns a standard AsyncSocket maxed out error.
  3538. **/
  3539. - (NSError *)readMaxedOutError
  3540. {
  3541.         NSString *errMsg = NSLocalizedStringWithDefaultValue(@"GCDAsyncSocketReadMaxedOutError",
  3542.                                                                                                                  @"GCDAsyncSocket", [NSBundle mainBundle],
  3543.                                                                                                                  @"Read operation reached set maximum length", nil);
  3544.        
  3545.         NSDictionary *info = @{NSLocalizedDescriptionKey : errMsg};
  3546.        
  3547.         return [NSError errorWithDomain:GCDAsyncSocketErrorDomain code:GCDAsyncSocketReadMaxedOutError userInfo:info];
  3548. }
  3549.  
  3550. /**
  3551.  * Returns a standard AsyncSocket write timeout error.
  3552. **/
  3553. - (NSError *)readTimeoutError
  3554. {
  3555.         NSString *errMsg = NSLocalizedStringWithDefaultValue(@"GCDAsyncSocketReadTimeoutError",
  3556.                                                              @"GCDAsyncSocket", [NSBundle mainBundle],
  3557.                                                              @"Read operation timed out", nil);
  3558.        
  3559.         NSDictionary *userInfo = @{NSLocalizedDescriptionKey : errMsg};
  3560.        
  3561.         return [NSError errorWithDomain:GCDAsyncSocketErrorDomain code:GCDAsyncSocketReadTimeoutError userInfo:userInfo];
  3562. }
  3563.  
  3564. /**
  3565.  * Returns a standard AsyncSocket write timeout error.
  3566. **/
  3567. - (NSError *)writeTimeoutError
  3568. {
  3569.         NSString *errMsg = NSLocalizedStringWithDefaultValue(@"GCDAsyncSocketWriteTimeoutError",
  3570.                                                              @"GCDAsyncSocket", [NSBundle mainBundle],
  3571.                                                              @"Write operation timed out", nil);
  3572.        
  3573.         NSDictionary *userInfo = @{NSLocalizedDescriptionKey : errMsg};
  3574.        
  3575.         return [NSError errorWithDomain:GCDAsyncSocketErrorDomain code:GCDAsyncSocketWriteTimeoutError userInfo:userInfo];
  3576. }
  3577.  
  3578. - (NSError *)connectionClosedError
  3579. {
  3580.         NSString *errMsg = NSLocalizedStringWithDefaultValue(@"GCDAsyncSocketClosedError",
  3581.                                                              @"GCDAsyncSocket", [NSBundle mainBundle],
  3582.                                                              @"Socket closed by remote peer", nil);
  3583.        
  3584.         NSDictionary *userInfo = @{NSLocalizedDescriptionKey : errMsg};
  3585.        
  3586.         return [NSError errorWithDomain:GCDAsyncSocketErrorDomain code:GCDAsyncSocketClosedError userInfo:userInfo];
  3587. }
  3588.  
  3589. - (NSError *)otherError:(NSString *)errMsg
  3590. {
  3591.         NSDictionary *userInfo = @{NSLocalizedDescriptionKey : errMsg};
  3592.        
  3593.         return [NSError errorWithDomain:GCDAsyncSocketErrorDomain code:GCDAsyncSocketOtherError userInfo:userInfo];
  3594. }
  3595.  
  3596. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3597. #pragma mark Diagnostics
  3598. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3599.  
  3600. - (BOOL)isDisconnected
  3601. {
  3602.         __block BOOL result = NO;
  3603.        
  3604.         dispatch_block_t block = ^{
  3605.         result = (self->flags & kSocketStarted) ? NO : YES;
  3606.         };
  3607.        
  3608.         if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
  3609.                 block();
  3610.         else
  3611.                 dispatch_sync(socketQueue, block);
  3612.        
  3613.         return result;
  3614. }
  3615.  
  3616. - (BOOL)isConnected
  3617. {
  3618.         __block BOOL result = NO;
  3619.        
  3620.         dispatch_block_t block = ^{
  3621.         result = (self->flags & kConnected) ? YES : NO;
  3622.         };
  3623.        
  3624.         if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
  3625.                 block();
  3626.         else
  3627.                 dispatch_sync(socketQueue, block);
  3628.        
  3629.         return result;
  3630. }
  3631.  
  3632. - (NSString *)connectedHost
  3633. {
  3634.         if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
  3635.         {
  3636.                 if (socket4FD != SOCKET_NULL)
  3637.                         return [self connectedHostFromSocket4:socket4FD];
  3638.                 if (socket6FD != SOCKET_NULL)
  3639.                         return [self connectedHostFromSocket6:socket6FD];
  3640.                
  3641.                 return nil;
  3642.         }
  3643.         else
  3644.         {
  3645.                 __block NSString *result = nil;
  3646.                
  3647.                 dispatch_sync(socketQueue, ^{ @autoreleasepool {
  3648.                        
  3649.             if (self->socket4FD != SOCKET_NULL)
  3650.                 result = [self connectedHostFromSocket4:self->socket4FD];
  3651.             else if (self->socket6FD != SOCKET_NULL)
  3652.                 result = [self connectedHostFromSocket6:self->socket6FD];
  3653.                 }});
  3654.                
  3655.                 return result;
  3656.         }
  3657. }
  3658.  
  3659. - (uint16_t)connectedPort
  3660. {
  3661.         if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
  3662.         {
  3663.                 if (socket4FD != SOCKET_NULL)
  3664.                         return [self connectedPortFromSocket4:socket4FD];
  3665.                 if (socket6FD != SOCKET_NULL)
  3666.                         return [self connectedPortFromSocket6:socket6FD];
  3667.                
  3668.                 return 0;
  3669.         }
  3670.         else
  3671.         {
  3672.                 __block uint16_t result = 0;
  3673.                
  3674.                 dispatch_sync(socketQueue, ^{
  3675.                         // No need for autorelease pool
  3676.                        
  3677.             if (self->socket4FD != SOCKET_NULL)
  3678.                 result = [self connectedPortFromSocket4:self->socket4FD];
  3679.             else if (self->socket6FD != SOCKET_NULL)
  3680.                 result = [self connectedPortFromSocket6:self->socket6FD];
  3681.                 });
  3682.                
  3683.                 return result;
  3684.         }
  3685. }
  3686.  
  3687. - (NSURL *)connectedUrl
  3688. {
  3689.         if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
  3690.         {
  3691.                 if (socketUN != SOCKET_NULL)
  3692.                         return [self connectedUrlFromSocketUN:socketUN];
  3693.                
  3694.                 return nil;
  3695.         }
  3696.         else
  3697.         {
  3698.                 __block NSURL *result = nil;
  3699.                
  3700.                 dispatch_sync(socketQueue, ^{ @autoreleasepool {
  3701.                        
  3702.             if (self->socketUN != SOCKET_NULL)
  3703.                 result = [self connectedUrlFromSocketUN:self->socketUN];
  3704.                 }});
  3705.                
  3706.                 return result;
  3707.         }
  3708. }
  3709.  
  3710. - (NSString *)localHost
  3711. {
  3712.         if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
  3713.         {
  3714.                 if (socket4FD != SOCKET_NULL)
  3715.                         return [self localHostFromSocket4:socket4FD];
  3716.                 if (socket6FD != SOCKET_NULL)
  3717.                         return [self localHostFromSocket6:socket6FD];
  3718.                
  3719.                 return nil;
  3720.         }
  3721.         else
  3722.         {
  3723.                 __block NSString *result = nil;
  3724.                
  3725.                 dispatch_sync(socketQueue, ^{ @autoreleasepool {
  3726.                        
  3727.             if (self->socket4FD != SOCKET_NULL)
  3728.                 result = [self localHostFromSocket4:self->socket4FD];
  3729.             else if (self->socket6FD != SOCKET_NULL)
  3730.                 result = [self localHostFromSocket6:self->socket6FD];
  3731.                 }});
  3732.                
  3733.                 return result;
  3734.         }
  3735. }
  3736.  
  3737. - (uint16_t)localPort
  3738. {
  3739.         if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
  3740.         {
  3741.                 if (socket4FD != SOCKET_NULL)
  3742.                         return [self localPortFromSocket4:socket4FD];
  3743.                 if (socket6FD != SOCKET_NULL)
  3744.                         return [self localPortFromSocket6:socket6FD];
  3745.                
  3746.                 return 0;
  3747.         }
  3748.         else
  3749.         {
  3750.                 __block uint16_t result = 0;
  3751.                
  3752.                 dispatch_sync(socketQueue, ^{
  3753.                         // No need for autorelease pool
  3754.                        
  3755.             if (self->socket4FD != SOCKET_NULL)
  3756.                 result = [self localPortFromSocket4:self->socket4FD];
  3757.             else if (self->socket6FD != SOCKET_NULL)
  3758.                 result = [self localPortFromSocket6:self->socket6FD];
  3759.                 });
  3760.                
  3761.                 return result;
  3762.         }
  3763. }
  3764.  
  3765. - (NSString *)connectedHost4
  3766. {
  3767.         if (socket4FD != SOCKET_NULL)
  3768.                 return [self connectedHostFromSocket4:socket4FD];
  3769.        
  3770.         return nil;
  3771. }
  3772.  
  3773. - (NSString *)connectedHost6
  3774. {
  3775.         if (socket6FD != SOCKET_NULL)
  3776.                 return [self connectedHostFromSocket6:socket6FD];
  3777.        
  3778.         return nil;
  3779. }
  3780.  
  3781. - (uint16_t)connectedPort4
  3782. {
  3783.         if (socket4FD != SOCKET_NULL)
  3784.                 return [self connectedPortFromSocket4:socket4FD];
  3785.        
  3786.         return 0;
  3787. }
  3788.  
  3789. - (uint16_t)connectedPort6
  3790. {
  3791.         if (socket6FD != SOCKET_NULL)
  3792.                 return [self connectedPortFromSocket6:socket6FD];
  3793.        
  3794.         return 0;
  3795. }
  3796.  
  3797. - (NSString *)localHost4
  3798. {
  3799.         if (socket4FD != SOCKET_NULL)
  3800.                 return [self localHostFromSocket4:socket4FD];
  3801.        
  3802.         return nil;
  3803. }
  3804.  
  3805. - (NSString *)localHost6
  3806. {
  3807.         if (socket6FD != SOCKET_NULL)
  3808.                 return [self localHostFromSocket6:socket6FD];
  3809.        
  3810.         return nil;
  3811. }
  3812.  
  3813. - (uint16_t)localPort4
  3814. {
  3815.         if (socket4FD != SOCKET_NULL)
  3816.                 return [self localPortFromSocket4:socket4FD];
  3817.        
  3818.         return 0;
  3819. }
  3820.  
  3821. - (uint16_t)localPort6
  3822. {
  3823.         if (socket6FD != SOCKET_NULL)
  3824.                 return [self localPortFromSocket6:socket6FD];
  3825.        
  3826.         return 0;
  3827. }
  3828.  
  3829. - (NSString *)connectedHostFromSocket4:(int)socketFD
  3830. {
  3831.         struct sockaddr_in sockaddr4;
  3832.         socklen_t sockaddr4len = sizeof(sockaddr4);
  3833.        
  3834.         if (getpeername(socketFD, (struct sockaddr *)&sockaddr4, &sockaddr4len) < 0)
  3835.         {
  3836.                 return nil;
  3837.         }
  3838.         return [[self class] hostFromSockaddr4:&sockaddr4];
  3839. }
  3840.  
  3841. - (NSString *)connectedHostFromSocket6:(int)socketFD
  3842. {
  3843.         struct sockaddr_in6 sockaddr6;
  3844.         socklen_t sockaddr6len = sizeof(sockaddr6);
  3845.        
  3846.         if (getpeername(socketFD, (struct sockaddr *)&sockaddr6, &sockaddr6len) < 0)
  3847.         {
  3848.                 return nil;
  3849.         }
  3850.         return [[self class] hostFromSockaddr6:&sockaddr6];
  3851. }
  3852.  
  3853. - (uint16_t)connectedPortFromSocket4:(int)socketFD
  3854. {
  3855.         struct sockaddr_in sockaddr4;
  3856.         socklen_t sockaddr4len = sizeof(sockaddr4);
  3857.        
  3858.         if (getpeername(socketFD, (struct sockaddr *)&sockaddr4, &sockaddr4len) < 0)
  3859.         {
  3860.                 return 0;
  3861.         }
  3862.         return [[self class] portFromSockaddr4:&sockaddr4];
  3863. }
  3864.  
  3865. - (uint16_t)connectedPortFromSocket6:(int)socketFD
  3866. {
  3867.         struct sockaddr_in6 sockaddr6;
  3868.         socklen_t sockaddr6len = sizeof(sockaddr6);
  3869.        
  3870.         if (getpeername(socketFD, (struct sockaddr *)&sockaddr6, &sockaddr6len) < 0)
  3871.         {
  3872.                 return 0;
  3873.         }
  3874.         return [[self class] portFromSockaddr6:&sockaddr6];
  3875. }
  3876.  
  3877. - (NSURL *)connectedUrlFromSocketUN:(int)socketFD
  3878. {
  3879.         struct sockaddr_un sockaddr;
  3880.         socklen_t sockaddrlen = sizeof(sockaddr);
  3881.        
  3882.         if (getpeername(socketFD, (struct sockaddr *)&sockaddr, &sockaddrlen) < 0)
  3883.         {
  3884.                 return 0;
  3885.         }
  3886.         return [[self class] urlFromSockaddrUN:&sockaddr];
  3887. }
  3888.  
  3889. - (NSString *)localHostFromSocket4:(int)socketFD
  3890. {
  3891.         struct sockaddr_in sockaddr4;
  3892.         socklen_t sockaddr4len = sizeof(sockaddr4);
  3893.        
  3894.         if (getsockname(socketFD, (struct sockaddr *)&sockaddr4, &sockaddr4len) < 0)
  3895.         {
  3896.                 return nil;
  3897.         }
  3898.         return [[self class] hostFromSockaddr4:&sockaddr4];
  3899. }
  3900.  
  3901. - (NSString *)localHostFromSocket6:(int)socketFD
  3902. {
  3903.         struct sockaddr_in6 sockaddr6;
  3904.         socklen_t sockaddr6len = sizeof(sockaddr6);
  3905.        
  3906.         if (getsockname(socketFD, (struct sockaddr *)&sockaddr6, &sockaddr6len) < 0)
  3907.         {
  3908.                 return nil;
  3909.         }
  3910.         return [[self class] hostFromSockaddr6:&sockaddr6];
  3911. }
  3912.  
  3913. - (uint16_t)localPortFromSocket4:(int)socketFD
  3914. {
  3915.         struct sockaddr_in sockaddr4;
  3916.         socklen_t sockaddr4len = sizeof(sockaddr4);
  3917.        
  3918.         if (getsockname(socketFD, (struct sockaddr *)&sockaddr4, &sockaddr4len) < 0)
  3919.         {
  3920.                 return 0;
  3921.         }
  3922.         return [[self class] portFromSockaddr4:&sockaddr4];
  3923. }
  3924.  
  3925. - (uint16_t)localPortFromSocket6:(int)socketFD
  3926. {
  3927.         struct sockaddr_in6 sockaddr6;
  3928.         socklen_t sockaddr6len = sizeof(sockaddr6);
  3929.        
  3930.         if (getsockname(socketFD, (struct sockaddr *)&sockaddr6, &sockaddr6len) < 0)
  3931.         {
  3932.                 return 0;
  3933.         }
  3934.         return [[self class] portFromSockaddr6:&sockaddr6];
  3935. }
  3936.  
  3937. - (NSData *)connectedAddress
  3938. {
  3939.         __block NSData *result = nil;
  3940.        
  3941.         dispatch_block_t block = ^{
  3942.         if (self->socket4FD != SOCKET_NULL)
  3943.                 {
  3944.                         struct sockaddr_in sockaddr4;
  3945.                         socklen_t sockaddr4len = sizeof(sockaddr4);
  3946.                        
  3947.             if (getpeername(self->socket4FD, (struct sockaddr *)&sockaddr4, &sockaddr4len) == 0)
  3948.                         {
  3949.                                 result = [[NSData alloc] initWithBytes:&sockaddr4 length:sockaddr4len];
  3950.                         }
  3951.                 }
  3952.                
  3953.         if (self->socket6FD != SOCKET_NULL)
  3954.                 {
  3955.                         struct sockaddr_in6 sockaddr6;
  3956.                         socklen_t sockaddr6len = sizeof(sockaddr6);
  3957.                        
  3958.             if (getpeername(self->socket6FD, (struct sockaddr *)&sockaddr6, &sockaddr6len) == 0)
  3959.                         {
  3960.                                 result = [[NSData alloc] initWithBytes:&sockaddr6 length:sockaddr6len];
  3961.                         }
  3962.                 }
  3963.         };
  3964.        
  3965.         if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
  3966.                 block();
  3967.         else
  3968.                 dispatch_sync(socketQueue, block);
  3969.        
  3970.         return result;
  3971. }
  3972.  
  3973. - (NSData *)localAddress
  3974. {
  3975.         __block NSData *result = nil;
  3976.        
  3977.         dispatch_block_t block = ^{
  3978.         if (self->socket4FD != SOCKET_NULL)
  3979.                 {
  3980.                         struct sockaddr_in sockaddr4;
  3981.                         socklen_t sockaddr4len = sizeof(sockaddr4);
  3982.                        
  3983.             if (getsockname(self->socket4FD, (struct sockaddr *)&sockaddr4, &sockaddr4len) == 0)
  3984.                         {
  3985.                                 result = [[NSData alloc] initWithBytes:&sockaddr4 length:sockaddr4len];
  3986.                         }
  3987.                 }
  3988.                
  3989.         if (self->socket6FD != SOCKET_NULL)
  3990.                 {
  3991.                         struct sockaddr_in6 sockaddr6;
  3992.                         socklen_t sockaddr6len = sizeof(sockaddr6);
  3993.                        
  3994.             if (getsockname(self->socket6FD, (struct sockaddr *)&sockaddr6, &sockaddr6len) == 0)
  3995.                         {
  3996.                                 result = [[NSData alloc] initWithBytes:&sockaddr6 length:sockaddr6len];
  3997.                         }
  3998.                 }
  3999.         };
  4000.        
  4001.         if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
  4002.                 block();
  4003.         else
  4004.                 dispatch_sync(socketQueue, block);
  4005.        
  4006.         return result;
  4007. }
  4008.  
  4009. - (BOOL)isIPv4
  4010. {
  4011.         if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
  4012.         {
  4013.                 return (socket4FD != SOCKET_NULL);
  4014.         }
  4015.         else
  4016.         {
  4017.                 __block BOOL result = NO;
  4018.                
  4019.                 dispatch_sync(socketQueue, ^{
  4020.             result = (self->socket4FD != SOCKET_NULL);
  4021.                 });
  4022.                
  4023.                 return result;
  4024.         }
  4025. }
  4026.  
  4027. - (BOOL)isIPv6
  4028. {
  4029.         if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
  4030.         {
  4031.                 return (socket6FD != SOCKET_NULL);
  4032.         }
  4033.         else
  4034.         {
  4035.                 __block BOOL result = NO;
  4036.                
  4037.                 dispatch_sync(socketQueue, ^{
  4038.             result = (self->socket6FD != SOCKET_NULL);
  4039.                 });
  4040.                
  4041.                 return result;
  4042.         }
  4043. }
  4044.  
  4045. - (BOOL)isSecure
  4046. {
  4047.         if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
  4048.         {
  4049.                 return (flags & kSocketSecure) ? YES : NO;
  4050.         }
  4051.         else
  4052.         {
  4053.                 __block BOOL result;
  4054.                
  4055.                 dispatch_sync(socketQueue, ^{
  4056.             result = (self->flags & kSocketSecure) ? YES : NO;
  4057.                 });
  4058.                
  4059.                 return result;
  4060.         }
  4061. }
  4062.  
  4063. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  4064. #pragma mark Utilities
  4065. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  4066.  
  4067. /**
  4068.  * Finds the address of an interface description.
  4069.  * An inteface description may be an interface name (en0, en1, lo0) or corresponding IP (192.168.4.34).
  4070.  *
  4071.  * The interface description may optionally contain a port number at the end, separated by a colon.
  4072.  * If a non-zero port parameter is provided, any port number in the interface description is ignored.
  4073.  *
  4074.  * The returned value is a 'struct sockaddr' wrapped in an NSMutableData object.
  4075. **/
  4076. - (void)getInterfaceAddress4:(NSMutableData **)interfaceAddr4Ptr
  4077.                     address6:(NSMutableData **)interfaceAddr6Ptr
  4078.              fromDescription:(NSString *)interfaceDescription
  4079.                         port:(uint16_t)port
  4080. {
  4081.         NSMutableData *addr4 = nil;
  4082.         NSMutableData *addr6 = nil;
  4083.        
  4084.         NSString *interface = nil;
  4085.        
  4086.         NSArray *components = [interfaceDescription componentsSeparatedByString:@":"];
  4087.         if ([components count] > 0)
  4088.         {
  4089.                 NSString *temp = [components objectAtIndex:0];
  4090.                 if ([temp length] > 0)
  4091.                 {
  4092.                         interface = temp;
  4093.                 }
  4094.         }
  4095.         if ([components count] > 1 && port == 0)
  4096.         {
  4097.                 NSString *temp = [components objectAtIndex:1];
  4098.                 long portL = strtol([temp UTF8String], NULL, 10);
  4099.                
  4100.                 if (portL > 0 && portL <= UINT16_MAX)
  4101.                 {
  4102.                         port = (uint16_t)portL;
  4103.                 }
  4104.         }
  4105.        
  4106.         if (interface == nil)
  4107.         {
  4108.                 // ANY address
  4109.                
  4110.                 struct sockaddr_in sockaddr4;
  4111.                 memset(&sockaddr4, 0, sizeof(sockaddr4));
  4112.                
  4113.                 sockaddr4.sin_len         = sizeof(sockaddr4);
  4114.                 sockaddr4.sin_family      = AF_INET;
  4115.                 sockaddr4.sin_port        = htons(port);
  4116.                 sockaddr4.sin_addr.s_addr = htonl(INADDR_ANY);
  4117.                
  4118.                 struct sockaddr_in6 sockaddr6;
  4119.                 memset(&sockaddr6, 0, sizeof(sockaddr6));
  4120.                
  4121.                 sockaddr6.sin6_len       = sizeof(sockaddr6);
  4122.                 sockaddr6.sin6_family    = AF_INET6;
  4123.                 sockaddr6.sin6_port      = htons(port);
  4124.                 sockaddr6.sin6_addr      = in6addr_any;
  4125.                
  4126.                 addr4 = [NSMutableData dataWithBytes:&sockaddr4 length:sizeof(sockaddr4)];
  4127.                 addr6 = [NSMutableData dataWithBytes:&sockaddr6 length:sizeof(sockaddr6)];
  4128.         }
  4129.         else if ([interface isEqualToString:@"localhost"] || [interface isEqualToString:@"loopback"])
  4130.         {
  4131.                 // LOOPBACK address
  4132.                
  4133.                 struct sockaddr_in sockaddr4;
  4134.                 memset(&sockaddr4, 0, sizeof(sockaddr4));
  4135.                
  4136.                 sockaddr4.sin_len         = sizeof(sockaddr4);
  4137.                 sockaddr4.sin_family      = AF_INET;
  4138.                 sockaddr4.sin_port        = htons(port);
  4139.                 sockaddr4.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
  4140.                
  4141.                 struct sockaddr_in6 sockaddr6;
  4142.                 memset(&sockaddr6, 0, sizeof(sockaddr6));
  4143.                
  4144.                 sockaddr6.sin6_len       = sizeof(sockaddr6);
  4145.                 sockaddr6.sin6_family    = AF_INET6;
  4146.                 sockaddr6.sin6_port      = htons(port);
  4147.                 sockaddr6.sin6_addr      = in6addr_loopback;
  4148.                
  4149.                 addr4 = [NSMutableData dataWithBytes:&sockaddr4 length:sizeof(sockaddr4)];
  4150.                 addr6 = [NSMutableData dataWithBytes:&sockaddr6 length:sizeof(sockaddr6)];
  4151.         }
  4152.         else
  4153.         {
  4154.                 const char *iface = [interface UTF8String];
  4155.                
  4156.                 struct ifaddrs *addrs;
  4157.                 const struct ifaddrs *cursor;
  4158.                
  4159.                 if ((getifaddrs(&addrs) == 0))
  4160.                 {
  4161.                         cursor = addrs;
  4162.                         while (cursor != NULL)
  4163.                         {
  4164.                                 if ((addr4 == nil) && (cursor->ifa_addr->sa_family == AF_INET))
  4165.                                 {
  4166.                                         // IPv4
  4167.                                        
  4168.                                         struct sockaddr_in nativeAddr4;
  4169.                                         memcpy(&nativeAddr4, cursor->ifa_addr, sizeof(nativeAddr4));
  4170.                                        
  4171.                                         if (strcmp(cursor->ifa_name, iface) == 0)
  4172.                                         {
  4173.                                                 // Name match
  4174.                                                
  4175.                                                 nativeAddr4.sin_port = htons(port);
  4176.                                                
  4177.                                                 addr4 = [NSMutableData dataWithBytes:&nativeAddr4 length:sizeof(nativeAddr4)];
  4178.                                         }
  4179.                                         else
  4180.                                         {
  4181.                                                 char ip[INET_ADDRSTRLEN];
  4182.                                                
  4183.                                                 const char *conversion = inet_ntop(AF_INET, &nativeAddr4.sin_addr, ip, sizeof(ip));
  4184.                                                
  4185.                                                 if ((conversion != NULL) && (strcmp(ip, iface) == 0))
  4186.                                                 {
  4187.                                                         // IP match
  4188.                                                        
  4189.                                                         nativeAddr4.sin_port = htons(port);
  4190.                                                        
  4191.                                                         addr4 = [NSMutableData dataWithBytes:&nativeAddr4 length:sizeof(nativeAddr4)];
  4192.                                                 }
  4193.                                         }
  4194.                                 }
  4195.                                 else if ((addr6 == nil) && (cursor->ifa_addr->sa_family == AF_INET6))
  4196.                                 {
  4197.                                         // IPv6
  4198.                                        
  4199.                                         struct sockaddr_in6 nativeAddr6;
  4200.                                         memcpy(&nativeAddr6, cursor->ifa_addr, sizeof(nativeAddr6));
  4201.                                        
  4202.                                         if (strcmp(cursor->ifa_name, iface) == 0)
  4203.                                         {
  4204.                                                 // Name match
  4205.                                                
  4206.                                                 nativeAddr6.sin6_port = htons(port);
  4207.                                                
  4208.                                                 addr6 = [NSMutableData dataWithBytes:&nativeAddr6 length:sizeof(nativeAddr6)];
  4209.                                         }
  4210.                                         else
  4211.                                         {
  4212.                                                 char ip[INET6_ADDRSTRLEN];
  4213.                                                
  4214.                                                 const char *conversion = inet_ntop(AF_INET6, &nativeAddr6.sin6_addr, ip, sizeof(ip));
  4215.                                                
  4216.                                                 if ((conversion != NULL) && (strcmp(ip, iface) == 0))
  4217.                                                 {
  4218.                                                         // IP match
  4219.                                                        
  4220.                                                         nativeAddr6.sin6_port = htons(port);
  4221.                                                        
  4222.                                                         addr6 = [NSMutableData dataWithBytes:&nativeAddr6 length:sizeof(nativeAddr6)];
  4223.                                                 }
  4224.                                         }
  4225.                                 }
  4226.                                
  4227.                                 cursor = cursor->ifa_next;
  4228.                         }
  4229.                        
  4230.                         freeifaddrs(addrs);
  4231.                 }
  4232.         }
  4233.        
  4234.         if (interfaceAddr4Ptr) *interfaceAddr4Ptr = addr4;
  4235.         if (interfaceAddr6Ptr) *interfaceAddr6Ptr = addr6;
  4236. }
  4237.  
  4238. - (NSData *)getInterfaceAddressFromUrl:(NSURL *)url
  4239. {
  4240.         NSString *path = url.path;
  4241.         if (path.length == 0) {
  4242.                 return nil;
  4243.         }
  4244.        
  4245.     struct sockaddr_un nativeAddr;
  4246.     nativeAddr.sun_family = AF_UNIX;
  4247.     strlcpy(nativeAddr.sun_path, path.fileSystemRepresentation, sizeof(nativeAddr.sun_path));
  4248.     nativeAddr.sun_len = (unsigned char)SUN_LEN(&nativeAddr);
  4249.     NSData *interface = [NSData dataWithBytes:&nativeAddr length:sizeof(struct sockaddr_un)];
  4250.        
  4251.         return interface;
  4252. }
  4253.  
  4254. - (void)setupReadAndWriteSourcesForNewlyConnectedSocket:(int)socketFD
  4255. {
  4256.         readSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, socketFD, 0, socketQueue);
  4257.         writeSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_WRITE, socketFD, 0, socketQueue);
  4258.        
  4259.         // Setup event handlers
  4260.        
  4261.         __weak GCDAsyncSocket *weakSelf = self;
  4262.        
  4263.         dispatch_source_set_event_handler(readSource, ^{ @autoreleasepool {
  4264.         #pragma clang diagnostic push
  4265.         #pragma clang diagnostic warning "-Wimplicit-retain-self"
  4266.                
  4267.                 __strong GCDAsyncSocket *strongSelf = weakSelf;
  4268.                 if (strongSelf == nil) return_from_block;
  4269.                
  4270.                 LogVerbose(@"readEventBlock");
  4271.                
  4272.                 strongSelf->socketFDBytesAvailable = dispatch_source_get_data(strongSelf->readSource);
  4273.                 LogVerbose(@"socketFDBytesAvailable: %lu", strongSelf->socketFDBytesAvailable);
  4274.                
  4275.                 if (strongSelf->socketFDBytesAvailable > 0)
  4276.                         [strongSelf doReadData];
  4277.                 else
  4278.                         [strongSelf doReadEOF];
  4279.                
  4280.         #pragma clang diagnostic pop
  4281.         }});
  4282.        
  4283.         dispatch_source_set_event_handler(writeSource, ^{ @autoreleasepool {
  4284.         #pragma clang diagnostic push
  4285.         #pragma clang diagnostic warning "-Wimplicit-retain-self"
  4286.                
  4287.                 __strong GCDAsyncSocket *strongSelf = weakSelf;
  4288.                 if (strongSelf == nil) return_from_block;
  4289.                
  4290.                 LogVerbose(@"writeEventBlock");
  4291.                
  4292.                 strongSelf->flags |= kSocketCanAcceptBytes;
  4293.                 [strongSelf doWriteData];
  4294.                
  4295.         #pragma clang diagnostic pop
  4296.         }});
  4297.        
  4298.         // Setup cancel handlers
  4299.        
  4300.         __block int socketFDRefCount = 2;
  4301.        
  4302.         #if !OS_OBJECT_USE_OBJC
  4303.         dispatch_source_t theReadSource = readSource;
  4304.         dispatch_source_t theWriteSource = writeSource;
  4305.         #endif
  4306.        
  4307.         dispatch_source_set_cancel_handler(readSource, ^{
  4308.         #pragma clang diagnostic push
  4309.         #pragma clang diagnostic warning "-Wimplicit-retain-self"
  4310.                
  4311.                 LogVerbose(@"readCancelBlock");
  4312.                
  4313.                 #if !OS_OBJECT_USE_OBJC
  4314.                 LogVerbose(@"dispatch_release(readSource)");
  4315.                 dispatch_release(theReadSource);
  4316.                 #endif
  4317.                
  4318.                 if (--socketFDRefCount == 0)
  4319.                 {
  4320.                         LogVerbose(@"close(socketFD)");
  4321.                         close(socketFD);
  4322.                 }
  4323.                
  4324.         #pragma clang diagnostic pop
  4325.         });
  4326.        
  4327.         dispatch_source_set_cancel_handler(writeSource, ^{
  4328.         #pragma clang diagnostic push
  4329.         #pragma clang diagnostic warning "-Wimplicit-retain-self"
  4330.                
  4331.                 LogVerbose(@"writeCancelBlock");
  4332.                
  4333.                 #if !OS_OBJECT_USE_OBJC
  4334.                 LogVerbose(@"dispatch_release(writeSource)");
  4335.                 dispatch_release(theWriteSource);
  4336.                 #endif
  4337.                
  4338.                 if (--socketFDRefCount == 0)
  4339.                 {
  4340.                         LogVerbose(@"close(socketFD)");
  4341.                         close(socketFD);
  4342.                 }
  4343.                
  4344.         #pragma clang diagnostic pop
  4345.         });
  4346.        
  4347.         // We will not be able to read until data arrives.
  4348.         // But we should be able to write immediately.
  4349.        
  4350.         socketFDBytesAvailable = 0;
  4351.         flags &= ~kReadSourceSuspended;
  4352.        
  4353.         LogVerbose(@"dispatch_resume(readSource)");
  4354.         dispatch_resume(readSource);
  4355.        
  4356.         flags |= kSocketCanAcceptBytes;
  4357.         flags |= kWriteSourceSuspended;
  4358. }
  4359.  
  4360. - (BOOL)usingCFStreamForTLS
  4361. {
  4362.         #if TARGET_OS_IPHONE
  4363.        
  4364.         if ((flags & kSocketSecure) && (flags & kUsingCFStreamForTLS))
  4365.         {
  4366.                 // The startTLS method was given the GCDAsyncSocketUseCFStreamForTLS flag.
  4367.                
  4368.                 return YES;
  4369.         }
  4370.        
  4371.         #endif
  4372.        
  4373.         return NO;
  4374. }
  4375.  
  4376. - (BOOL)usingSecureTransportForTLS
  4377. {
  4378.         // Invoking this method is equivalent to ![self usingCFStreamForTLS] (just more readable)
  4379.        
  4380.         #if TARGET_OS_IPHONE
  4381.        
  4382.         if ((flags & kSocketSecure) && (flags & kUsingCFStreamForTLS))
  4383.         {
  4384.                 // The startTLS method was given the GCDAsyncSocketUseCFStreamForTLS flag.
  4385.                
  4386.                 return NO;
  4387.         }
  4388.        
  4389.         #endif
  4390.        
  4391.         return YES;
  4392. }
  4393.  
  4394. - (void)suspendReadSource
  4395. {
  4396.         if (!(flags & kReadSourceSuspended))
  4397.         {
  4398.                 LogVerbose(@"dispatch_suspend(readSource)");
  4399.                
  4400.                 dispatch_suspend(readSource);
  4401.                 flags |= kReadSourceSuspended;
  4402.         }
  4403. }
  4404.  
  4405. - (void)resumeReadSource
  4406. {
  4407.         if (flags & kReadSourceSuspended)
  4408.         {
  4409.                 LogVerbose(@"dispatch_resume(readSource)");
  4410.                
  4411.                 dispatch_resume(readSource);
  4412.                 flags &= ~kReadSourceSuspended;
  4413.         }
  4414. }
  4415.  
  4416. - (void)suspendWriteSource
  4417. {
  4418.         if (!(flags & kWriteSourceSuspended))
  4419.         {
  4420.                 LogVerbose(@"dispatch_suspend(writeSource)");
  4421.                
  4422.                 dispatch_suspend(writeSource);
  4423.                 flags |= kWriteSourceSuspended;
  4424.         }
  4425. }
  4426.  
  4427. - (void)resumeWriteSource
  4428. {
  4429.         if (flags & kWriteSourceSuspended)
  4430.         {
  4431.                 LogVerbose(@"dispatch_resume(writeSource)");
  4432.                
  4433.                 dispatch_resume(writeSource);
  4434.                 flags &= ~kWriteSourceSuspended;
  4435.         }
  4436. }
  4437.  
  4438. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  4439. #pragma mark Reading
  4440. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  4441.  
  4442. - (void)readDataWithTimeout:(NSTimeInterval)timeout tag:(long)tag
  4443. {
  4444.         [self readDataWithTimeout:timeout buffer:nil bufferOffset:0 maxLength:0 tag:tag];
  4445. }
  4446.  
  4447. - (void)readDataWithTimeout:(NSTimeInterval)timeout
  4448.                      buffer:(NSMutableData *)buffer
  4449.                bufferOffset:(NSUInteger)offset
  4450.                         tag:(long)tag
  4451. {
  4452.         [self readDataWithTimeout:timeout buffer:buffer bufferOffset:offset maxLength:0 tag:tag];
  4453. }
  4454.  
  4455. - (void)readDataWithTimeout:(NSTimeInterval)timeout
  4456.                      buffer:(NSMutableData *)buffer
  4457.                bufferOffset:(NSUInteger)offset
  4458.                   maxLength:(NSUInteger)length
  4459.                         tag:(long)tag
  4460. {
  4461.         if (offset > [buffer length]) {
  4462.                 LogWarn(@"Cannot read: offset > [buffer length]");
  4463.                 return;
  4464.         }
  4465.        
  4466.         GCDAsyncReadPacket *packet = [[GCDAsyncReadPacket alloc] initWithData:buffer
  4467.                                                                   startOffset:offset
  4468.                                                                     maxLength:length
  4469.                                                                       timeout:timeout
  4470.                                                                    readLength:0
  4471.                                                                    terminator:nil
  4472.                                                                           tag:tag];
  4473.        
  4474.         dispatch_async(socketQueue, ^{ @autoreleasepool {
  4475.                
  4476.                 LogTrace();
  4477.                
  4478.         if ((self->flags & kSocketStarted) && !(self->flags & kForbidReadsWrites))
  4479.                 {
  4480.             [self->readQueue addObject:packet];
  4481.                         [self maybeDequeueRead];
  4482.                 }
  4483.         }});
  4484.        
  4485.         // Do not rely on the block being run in order to release the packet,
  4486.         // as the queue might get released without the block completing.
  4487. }
  4488.  
  4489. - (void)readDataToLength:(NSUInteger)length withTimeout:(NSTimeInterval)timeout tag:(long)tag
  4490. {
  4491.         [self readDataToLength:length withTimeout:timeout buffer:nil bufferOffset:0 tag:tag];
  4492. }
  4493.  
  4494. - (void)readDataToLength:(NSUInteger)length
  4495.              withTimeout:(NSTimeInterval)timeout
  4496.                   buffer:(NSMutableData *)buffer
  4497.             bufferOffset:(NSUInteger)offset
  4498.                      tag:(long)tag
  4499. {
  4500.         if (length == 0) {
  4501.                 LogWarn(@"Cannot read: length == 0");
  4502.                 return;
  4503.         }
  4504.         if (offset > [buffer length]) {
  4505.                 LogWarn(@"Cannot read: offset > [buffer length]");
  4506.                 return;
  4507.         }
  4508.        
  4509.         GCDAsyncReadPacket *packet = [[GCDAsyncReadPacket alloc] initWithData:buffer
  4510.                                                                   startOffset:offset
  4511.                                                                     maxLength:0
  4512.                                                                       timeout:timeout
  4513.                                                                    readLength:length
  4514.                                                                    terminator:nil
  4515.                                                                           tag:tag];
  4516.        
  4517.         dispatch_async(socketQueue, ^{ @autoreleasepool {
  4518.                
  4519.                 LogTrace();
  4520.                
  4521.         if ((self->flags & kSocketStarted) && !(self->flags & kForbidReadsWrites))
  4522.                 {
  4523.             [self->readQueue addObject:packet];
  4524.                         [self maybeDequeueRead];
  4525.                 }
  4526.         }});
  4527.        
  4528.         // Do not rely on the block being run in order to release the packet,
  4529.         // as the queue might get released without the block completing.
  4530. }
  4531.  
  4532. - (void)readDataToData:(NSData *)data withTimeout:(NSTimeInterval)timeout tag:(long)tag
  4533. {
  4534.         [self readDataToData:data withTimeout:timeout buffer:nil bufferOffset:0 maxLength:0 tag:tag];
  4535. }
  4536.  
  4537. - (void)readDataToData:(NSData *)data
  4538.            withTimeout:(NSTimeInterval)timeout
  4539.                 buffer:(NSMutableData *)buffer
  4540.           bufferOffset:(NSUInteger)offset
  4541.                    tag:(long)tag
  4542. {
  4543.         [self readDataToData:data withTimeout:timeout buffer:buffer bufferOffset:offset maxLength:0 tag:tag];
  4544. }
  4545.  
  4546. - (void)readDataToData:(NSData *)data withTimeout:(NSTimeInterval)timeout maxLength:(NSUInteger)length tag:(long)tag
  4547. {
  4548.         [self readDataToData:data withTimeout:timeout buffer:nil bufferOffset:0 maxLength:length tag:tag];
  4549. }
  4550.  
  4551. - (void)readDataToData:(NSData *)data
  4552.            withTimeout:(NSTimeInterval)timeout
  4553.                 buffer:(NSMutableData *)buffer
  4554.           bufferOffset:(NSUInteger)offset
  4555.              maxLength:(NSUInteger)maxLength
  4556.                    tag:(long)tag
  4557. {
  4558.         if ([data length] == 0) {
  4559.                 LogWarn(@"Cannot read: [data length] == 0");
  4560.                 return;
  4561.         }
  4562.         if (offset > [buffer length]) {
  4563.                 LogWarn(@"Cannot read: offset > [buffer length]");
  4564.                 return;
  4565.         }
  4566.         if (maxLength > 0 && maxLength < [data length]) {
  4567.                 LogWarn(@"Cannot read: maxLength > 0 && maxLength < [data length]");
  4568.                 return;
  4569.         }
  4570.        
  4571.         GCDAsyncReadPacket *packet = [[GCDAsyncReadPacket alloc] initWithData:buffer
  4572.                                                                   startOffset:offset
  4573.                                                                     maxLength:maxLength
  4574.                                                                       timeout:timeout
  4575.                                                                    readLength:0
  4576.                                                                    terminator:data
  4577.                                                                           tag:tag];
  4578.        
  4579.         dispatch_async(socketQueue, ^{ @autoreleasepool {
  4580.                
  4581.                 LogTrace();
  4582.                
  4583.         if ((self->flags & kSocketStarted) && !(self->flags & kForbidReadsWrites))
  4584.                 {
  4585.             [self->readQueue addObject:packet];
  4586.                         [self maybeDequeueRead];
  4587.                 }
  4588.         }});
  4589.        
  4590.         // Do not rely on the block being run in order to release the packet,
  4591.         // as the queue might get released without the block completing.
  4592. }
  4593.  
  4594. - (float)progressOfReadReturningTag:(long *)tagPtr bytesDone:(NSUInteger *)donePtr total:(NSUInteger *)totalPtr
  4595. {
  4596.         __block float result = 0.0F;
  4597.        
  4598.         dispatch_block_t block = ^{
  4599.                
  4600.         if (!self->currentRead || ![self->currentRead isKindOfClass:[GCDAsyncReadPacket class]])
  4601.                 {
  4602.                         // We're not reading anything right now.
  4603.                        
  4604.                         if (tagPtr != NULL)   *tagPtr = 0;
  4605.                         if (donePtr != NULL)  *donePtr = 0;
  4606.                         if (totalPtr != NULL) *totalPtr = 0;
  4607.                        
  4608.                         result = NAN;
  4609.                 }
  4610.                 else
  4611.                 {
  4612.                         // It's only possible to know the progress of our read if we're reading to a certain length.
  4613.                         // If we're reading to data, we of course have no idea when the data will arrive.
  4614.                         // If we're reading to timeout, then we have no idea when the next chunk of data will arrive.
  4615.                        
  4616.             NSUInteger done = self->currentRead->bytesDone;
  4617.             NSUInteger total = self->currentRead->readLength;
  4618.                        
  4619.             if (tagPtr != NULL)   *tagPtr = self->currentRead->tag;
  4620.                         if (donePtr != NULL)  *donePtr = done;
  4621.                         if (totalPtr != NULL) *totalPtr = total;
  4622.                        
  4623.                         if (total > 0)
  4624.                                 result = (float)done / (float)total;
  4625.                         else
  4626.                                 result = 1.0F;
  4627.                 }
  4628.         };
  4629.        
  4630.         if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
  4631.                 block();
  4632.         else
  4633.                 dispatch_sync(socketQueue, block);
  4634.        
  4635.         return result;
  4636. }
  4637.  
  4638. /**
  4639.  * This method starts a new read, if needed.
  4640.  *
  4641.  * It is called when:
  4642.  * - a user requests a read
  4643.  * - after a read request has finished (to handle the next request)
  4644.  * - immediately after the socket opens to handle any pending requests
  4645.  *
  4646.  * This method also handles auto-disconnect post read/write completion.
  4647. **/
  4648. - (void)maybeDequeueRead
  4649. {
  4650.         LogTrace();
  4651.         NSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @"Must be dispatched on socketQueue");
  4652.        
  4653.         // If we're not currently processing a read AND we have an available read stream
  4654.         if ((currentRead == nil) && (flags & kConnected))
  4655.         {
  4656.                 if ([readQueue count] > 0)
  4657.                 {
  4658.                         // Dequeue the next object in the write queue
  4659.                         currentRead = [readQueue objectAtIndex:0];
  4660.                         [readQueue removeObjectAtIndex:0];
  4661.                        
  4662.                        
  4663.                         if ([currentRead isKindOfClass:[GCDAsyncSpecialPacket class]])
  4664.                         {
  4665.                                 LogVerbose(@"Dequeued GCDAsyncSpecialPacket");
  4666.                                
  4667.                                 // Attempt to start TLS
  4668.                                 flags |= kStartingReadTLS;
  4669.                                
  4670.                                 // This method won't do anything unless both kStartingReadTLS and kStartingWriteTLS are set
  4671.                                 [self maybeStartTLS];
  4672.                         }
  4673.                         else
  4674.                         {
  4675.                                 LogVerbose(@"Dequeued GCDAsyncReadPacket");
  4676.                                
  4677.                                 // Setup read timer (if needed)
  4678.                                 [self setupReadTimerWithTimeout:currentRead->timeout];
  4679.                                
  4680.                                 // Immediately read, if possible
  4681.                                 [self doReadData];
  4682.                         }
  4683.                 }
  4684.                 else if (flags & kDisconnectAfterReads)
  4685.                 {
  4686.                         if (flags & kDisconnectAfterWrites)
  4687.                         {
  4688.                                 if (([writeQueue count] == 0) && (currentWrite == nil))
  4689.                                 {
  4690.                                         [self closeWithError:nil];
  4691.                                 }
  4692.                         }
  4693.                         else
  4694.                         {
  4695.                                 [self closeWithError:nil];
  4696.                         }
  4697.                 }
  4698.                 else if (flags & kSocketSecure)
  4699.                 {
  4700.                         [self flushSSLBuffers];
  4701.                        
  4702.                         // Edge case:
  4703.                         //
  4704.                         // We just drained all data from the ssl buffers,
  4705.                         // and all known data from the socket (socketFDBytesAvailable).
  4706.                         //
  4707.                         // If we didn't get any data from this process,
  4708.                         // then we may have reached the end of the TCP stream.
  4709.                         //
  4710.                         // Be sure callbacks are enabled so we're notified about a disconnection.
  4711.                        
  4712.                         if ([preBuffer availableBytes] == 0)
  4713.                         {
  4714.                                 if ([self usingCFStreamForTLS]) {
  4715.                                         // Callbacks never disabled
  4716.                                 }
  4717.                                 else {
  4718.                                         [self resumeReadSource];
  4719.                                 }
  4720.                         }
  4721.                 }
  4722.         }
  4723. }
  4724.  
  4725. - (void)flushSSLBuffers
  4726. {
  4727.         LogTrace();
  4728.        
  4729.         NSAssert((flags & kSocketSecure), @"Cannot flush ssl buffers on non-secure socket");
  4730.        
  4731.         if ([preBuffer availableBytes] > 0)
  4732.         {
  4733.                 // Only flush the ssl buffers if the prebuffer is empty.
  4734.                 // This is to avoid growing the prebuffer inifinitely large.
  4735.                
  4736.                 return;
  4737.         }
  4738.        
  4739.         #if TARGET_OS_IPHONE
  4740.        
  4741.         if ([self usingCFStreamForTLS])
  4742.         {
  4743.                 if ((flags & kSecureSocketHasBytesAvailable) && CFReadStreamHasBytesAvailable(readStream))
  4744.                 {
  4745.                         LogVerbose(@"%@ - Flushing ssl buffers into prebuffer...", THIS_METHOD);
  4746.                        
  4747.                         CFIndex defaultBytesToRead = (1024 * 4);
  4748.                        
  4749.                         [preBuffer ensureCapacityForWrite:defaultBytesToRead];
  4750.                        
  4751.                         uint8_t *buffer = [preBuffer writeBuffer];
  4752.                        
  4753.                         CFIndex result = CFReadStreamRead(readStream, buffer, defaultBytesToRead);
  4754.                         LogVerbose(@"%@ - CFReadStreamRead(): result = %i", THIS_METHOD, (int)result);
  4755.                        
  4756.                         if (result > 0)
  4757.                         {
  4758.                                 [preBuffer didWrite:result];
  4759.                         }
  4760.                        
  4761.                         flags &= ~kSecureSocketHasBytesAvailable;
  4762.                 }
  4763.                
  4764.                 return;
  4765.         }
  4766.        
  4767.         #endif
  4768.        
  4769.         __block NSUInteger estimatedBytesAvailable = 0;
  4770.        
  4771.         dispatch_block_t updateEstimatedBytesAvailable = ^{
  4772.                
  4773.                 // Figure out if there is any data available to be read
  4774.                 //
  4775.                 // socketFDBytesAvailable        <- Number of encrypted bytes we haven't read from the bsd socket
  4776.                 // [sslPreBuffer availableBytes] <- Number of encrypted bytes we've buffered from bsd socket
  4777.                 // sslInternalBufSize            <- Number of decrypted bytes SecureTransport has buffered
  4778.                 //
  4779.                 // We call the variable "estimated" because we don't know how many decrypted bytes we'll get
  4780.                 // from the encrypted bytes in the sslPreBuffer.
  4781.                 // However, we do know this is an upper bound on the estimation.
  4782.                
  4783.         estimatedBytesAvailable = self->socketFDBytesAvailable + [self->sslPreBuffer availableBytes];
  4784.                
  4785.                 size_t sslInternalBufSize = 0;
  4786.         SSLGetBufferedReadSize(self->sslContext, &sslInternalBufSize);
  4787.                
  4788.                 estimatedBytesAvailable += sslInternalBufSize;
  4789.         };
  4790.        
  4791.         updateEstimatedBytesAvailable();
  4792.        
  4793.         if (estimatedBytesAvailable > 0)
  4794.         {
  4795.                 LogVerbose(@"%@ - Flushing ssl buffers into prebuffer...", THIS_METHOD);
  4796.                
  4797.                 BOOL done = NO;
  4798.                 do
  4799.                 {
  4800.                         LogVerbose(@"%@ - estimatedBytesAvailable = %lu", THIS_METHOD, (unsigned long)estimatedBytesAvailable);
  4801.                        
  4802.                         // Make sure there's enough room in the prebuffer
  4803.                        
  4804.                         [preBuffer ensureCapacityForWrite:estimatedBytesAvailable];
  4805.                        
  4806.                         // Read data into prebuffer
  4807.                        
  4808.                         uint8_t *buffer = [preBuffer writeBuffer];
  4809.                         size_t bytesRead = 0;
  4810.                        
  4811.                         OSStatus result = SSLRead(sslContext, buffer, (size_t)estimatedBytesAvailable, &bytesRead);
  4812.                         LogVerbose(@"%@ - read from secure socket = %u", THIS_METHOD, (unsigned)bytesRead);
  4813.                        
  4814.                         if (bytesRead > 0)
  4815.                         {
  4816.                                 [preBuffer didWrite:bytesRead];
  4817.                         }
  4818.                        
  4819.                         LogVerbose(@"%@ - prebuffer.length = %zu", THIS_METHOD, [preBuffer availableBytes]);
  4820.                        
  4821.                         if (result != noErr)
  4822.                         {
  4823.                                 done = YES;
  4824.                         }
  4825.                         else
  4826.                         {
  4827.                                 updateEstimatedBytesAvailable();
  4828.                         }
  4829.                        
  4830.                 } while (!done && estimatedBytesAvailable > 0);
  4831.         }
  4832. }
  4833.  
  4834. - (void)doReadData
  4835. {
  4836.         LogTrace();
  4837.        
  4838.         // This method is called on the socketQueue.
  4839.         // It might be called directly, or via the readSource when data is available to be read.
  4840.        
  4841.         if ((currentRead == nil) || (flags & kReadsPaused))
  4842.         {
  4843.                 LogVerbose(@"No currentRead or kReadsPaused");
  4844.                
  4845.                 // Unable to read at this time
  4846.                
  4847.                 if (flags & kSocketSecure)
  4848.                 {
  4849.                         // Here's the situation:
  4850.                         //
  4851.                         // We have an established secure connection.
  4852.                         // There may not be a currentRead, but there might be encrypted data sitting around for us.
  4853.                         // When the user does get around to issuing a read, that encrypted data will need to be decrypted.
  4854.                         //
  4855.                         // So why make the user wait?
  4856.                         // We might as well get a head start on decrypting some data now.
  4857.                         //
  4858.                         // The other reason we do this has to do with detecting a socket disconnection.
  4859.                         // The SSL/TLS protocol has it's own disconnection handshake.
  4860.                         // So when a secure socket is closed, a "goodbye" packet comes across the wire.
  4861.                         // We want to make sure we read the "goodbye" packet so we can properly detect the TCP disconnection.
  4862.                        
  4863.                         [self flushSSLBuffers];
  4864.                 }
  4865.                
  4866.                 if ([self usingCFStreamForTLS])
  4867.                 {
  4868.                         // CFReadStream only fires once when there is available data.
  4869.                         // It won't fire again until we've invoked CFReadStreamRead.
  4870.                 }
  4871.                 else
  4872.                 {
  4873.                         // If the readSource is firing, we need to pause it
  4874.                         // or else it will continue to fire over and over again.
  4875.                         //
  4876.                         // If the readSource is not firing,
  4877.                         // we want it to continue monitoring the socket.
  4878.                        
  4879.                         if (socketFDBytesAvailable > 0)
  4880.                         {
  4881.                                 [self suspendReadSource];
  4882.                         }
  4883.                 }
  4884.                 return;
  4885.         }
  4886.        
  4887.         BOOL hasBytesAvailable = NO;
  4888.         unsigned long estimatedBytesAvailable = 0;
  4889.        
  4890.         if ([self usingCFStreamForTLS])
  4891.         {
  4892.                 #if TARGET_OS_IPHONE
  4893.                
  4894.                 // Requested CFStream, rather than SecureTransport, for TLS (via GCDAsyncSocketUseCFStreamForTLS)
  4895.                
  4896.                 estimatedBytesAvailable = 0;
  4897.                 if ((flags & kSecureSocketHasBytesAvailable) && CFReadStreamHasBytesAvailable(readStream))
  4898.                         hasBytesAvailable = YES;
  4899.                 else
  4900.                         hasBytesAvailable = NO;
  4901.                
  4902.                 #endif
  4903.         }
  4904.         else
  4905.         {
  4906.                 estimatedBytesAvailable = socketFDBytesAvailable;
  4907.                
  4908.                 if (flags & kSocketSecure)
  4909.                 {
  4910.                         // There are 2 buffers to be aware of here.
  4911.                         //
  4912.                         // We are using SecureTransport, a TLS/SSL security layer which sits atop TCP.
  4913.                         // We issue a read to the SecureTranport API, which in turn issues a read to our SSLReadFunction.
  4914.                         // Our SSLReadFunction then reads from the BSD socket and returns the encrypted data to SecureTransport.
  4915.                         // SecureTransport then decrypts the data, and finally returns the decrypted data back to us.
  4916.                         //
  4917.                         // The first buffer is one we create.
  4918.                         // SecureTransport often requests small amounts of data.
  4919.                         // This has to do with the encypted packets that are coming across the TCP stream.
  4920.                         // But it's non-optimal to do a bunch of small reads from the BSD socket.
  4921.                         // So our SSLReadFunction reads all available data from the socket (optimizing the sys call)
  4922.                         // and may store excess in the sslPreBuffer.
  4923.                        
  4924.                         estimatedBytesAvailable += [sslPreBuffer availableBytes];
  4925.                        
  4926.                         // The second buffer is within SecureTransport.
  4927.                         // As mentioned earlier, there are encrypted packets coming across the TCP stream.
  4928.                         // SecureTransport needs the entire packet to decrypt it.
  4929.                         // But if the entire packet produces X bytes of decrypted data,
  4930.                         // and we only asked SecureTransport for X/2 bytes of data,
  4931.                         // it must store the extra X/2 bytes of decrypted data for the next read.
  4932.                         //
  4933.                         // The SSLGetBufferedReadSize function will tell us the size of this internal buffer.
  4934.                         // From the documentation:
  4935.                         //
  4936.                         // "This function does not block or cause any low-level read operations to occur."
  4937.                        
  4938.                         size_t sslInternalBufSize = 0;
  4939.                         SSLGetBufferedReadSize(sslContext, &sslInternalBufSize);
  4940.                        
  4941.                         estimatedBytesAvailable += sslInternalBufSize;
  4942.                 }
  4943.                
  4944.                 hasBytesAvailable = (estimatedBytesAvailable > 0);
  4945.         }
  4946.        
  4947.         if ((hasBytesAvailable == NO) && ([preBuffer availableBytes] == 0))
  4948.         {
  4949.                 LogVerbose(@"No data available to read...");
  4950.                
  4951.                 // No data available to read.
  4952.                
  4953.                 if (![self usingCFStreamForTLS])
  4954.                 {
  4955.                         // Need to wait for readSource to fire and notify us of
  4956.                         // available data in the socket's internal read buffer.
  4957.                        
  4958.                         [self resumeReadSource];
  4959.                 }
  4960.                 return;
  4961.         }
  4962.        
  4963.         if (flags & kStartingReadTLS)
  4964.         {
  4965.                 LogVerbose(@"Waiting for SSL/TLS handshake to complete");
  4966.                
  4967.                 // The readQueue is waiting for SSL/TLS handshake to complete.
  4968.                
  4969.                 if (flags & kStartingWriteTLS)
  4970.                 {
  4971.                         if ([self usingSecureTransportForTLS] && lastSSLHandshakeError == errSSLWouldBlock)
  4972.                         {
  4973.                                 // We are in the process of a SSL Handshake.
  4974.                                 // We were waiting for incoming data which has just arrived.
  4975.                                
  4976.                                 [self ssl_continueSSLHandshake];
  4977.                         }
  4978.                 }
  4979.                 else
  4980.                 {
  4981.                         // We are still waiting for the writeQueue to drain and start the SSL/TLS process.
  4982.                         // We now know data is available to read.
  4983.                        
  4984.                         if (![self usingCFStreamForTLS])
  4985.                         {
  4986.                                 // Suspend the read source or else it will continue to fire nonstop.
  4987.                                
  4988.                                 [self suspendReadSource];
  4989.                         }
  4990.                 }
  4991.                
  4992.                 return;
  4993.         }
  4994.        
  4995.         BOOL done        = NO;  // Completed read operation
  4996.         NSError *error   = nil; // Error occurred
  4997.        
  4998.         NSUInteger totalBytesReadForCurrentRead = 0;
  4999.        
  5000.         //
  5001.         // STEP 1 - READ FROM PREBUFFER
  5002.         //
  5003.        
  5004.         if ([preBuffer availableBytes] > 0)
  5005.         {
  5006.                 // There are 3 types of read packets:
  5007.                 //
  5008.                 // 1) Read all available data.
  5009.                 // 2) Read a specific length of data.
  5010.                 // 3) Read up to a particular terminator.
  5011.                
  5012.                 NSUInteger bytesToCopy;
  5013.                
  5014.                 if (currentRead->term != nil)
  5015.                 {
  5016.                         // Read type #3 - read up to a terminator
  5017.                        
  5018.                         bytesToCopy = [currentRead readLengthForTermWithPreBuffer:preBuffer found:&done];
  5019.                 }
  5020.                 else
  5021.                 {
  5022.                         // Read type #1 or #2
  5023.                        
  5024.                         bytesToCopy = [currentRead readLengthForNonTermWithHint:[preBuffer availableBytes]];
  5025.                 }
  5026.                
  5027.                 // Make sure we have enough room in the buffer for our read.
  5028.                
  5029.                 [currentRead ensureCapacityForAdditionalDataOfLength:bytesToCopy];
  5030.                
  5031.                 // Copy bytes from prebuffer into packet buffer
  5032.                
  5033.                 uint8_t *buffer = (uint8_t *)[currentRead->buffer mutableBytes] + currentRead->startOffset +
  5034.                                                                                   currentRead->bytesDone;
  5035.                
  5036.                 memcpy(buffer, [preBuffer readBuffer], bytesToCopy);
  5037.                
  5038.                 // Remove the copied bytes from the preBuffer
  5039.                 [preBuffer didRead:bytesToCopy];
  5040.                
  5041.                 LogVerbose(@"copied(%lu) preBufferLength(%zu)", (unsigned long)bytesToCopy, [preBuffer availableBytes]);
  5042.                
  5043.                 // Update totals
  5044.                
  5045.                 currentRead->bytesDone += bytesToCopy;
  5046.                 totalBytesReadForCurrentRead += bytesToCopy;
  5047.                
  5048.                 // Check to see if the read operation is done
  5049.                
  5050.                 if (currentRead->readLength > 0)
  5051.                 {
  5052.                         // Read type #2 - read a specific length of data
  5053.                        
  5054.                         done = (currentRead->bytesDone == currentRead->readLength);
  5055.                 }
  5056.                 else if (currentRead->term != nil)
  5057.                 {
  5058.                         // Read type #3 - read up to a terminator
  5059.                        
  5060.                         // Our 'done' variable was updated via the readLengthForTermWithPreBuffer:found: method
  5061.                        
  5062.                         if (!done && currentRead->maxLength > 0)
  5063.                         {
  5064.                                 // We're not done and there's a set maxLength.
  5065.                                 // Have we reached that maxLength yet?
  5066.                                
  5067.                                 if (currentRead->bytesDone >= currentRead->maxLength)
  5068.                                 {
  5069.                                         error = [self readMaxedOutError];
  5070.                                 }
  5071.                         }
  5072.                 }
  5073.                 else
  5074.                 {
  5075.                         // Read type #1 - read all available data
  5076.                         //
  5077.                         // We're done as soon as
  5078.                         // - we've read all available data (in prebuffer and socket)
  5079.                         // - we've read the maxLength of read packet.
  5080.                        
  5081.                         done = ((currentRead->maxLength > 0) && (currentRead->bytesDone == currentRead->maxLength));
  5082.                 }
  5083.                
  5084.         }
  5085.        
  5086.         //
  5087.         // STEP 2 - READ FROM SOCKET
  5088.         //
  5089.        
  5090.         BOOL socketEOF = (flags & kSocketHasReadEOF) ? YES : NO;  // Nothing more to read via socket (end of file)
  5091.         BOOL waiting   = !done && !error && !socketEOF && !hasBytesAvailable; // Ran out of data, waiting for more
  5092.        
  5093.         if (!done && !error && !socketEOF && hasBytesAvailable)
  5094.         {
  5095.                 NSAssert(([preBuffer availableBytes] == 0), @"Invalid logic");
  5096.                
  5097.                 BOOL readIntoPreBuffer = NO;
  5098.                 uint8_t *buffer = NULL;
  5099.                 size_t bytesRead = 0;
  5100.                
  5101.                 if (flags & kSocketSecure)
  5102.                 {
  5103.                         if ([self usingCFStreamForTLS])
  5104.                         {
  5105.                                 #if TARGET_OS_IPHONE
  5106.                                
  5107.                                 // Using CFStream, rather than SecureTransport, for TLS
  5108.                                
  5109.                                 NSUInteger defaultReadLength = (1024 * 32);
  5110.                                
  5111.                                 NSUInteger bytesToRead = [currentRead optimalReadLengthWithDefault:defaultReadLength
  5112.                                                                                    shouldPreBuffer:&readIntoPreBuffer];
  5113.                                
  5114.                                 // Make sure we have enough room in the buffer for our read.
  5115.                                 //
  5116.                                 // We are either reading directly into the currentRead->buffer,
  5117.                                 // or we're reading into the temporary preBuffer.
  5118.                                
  5119.                                 if (readIntoPreBuffer)
  5120.                                 {
  5121.                                         [preBuffer ensureCapacityForWrite:bytesToRead];
  5122.                                        
  5123.                                         buffer = [preBuffer writeBuffer];
  5124.                                 }
  5125.                                 else
  5126.                                 {
  5127.                                         [currentRead ensureCapacityForAdditionalDataOfLength:bytesToRead];
  5128.                                        
  5129.                                         buffer = (uint8_t *)[currentRead->buffer mutableBytes]
  5130.                                                + currentRead->startOffset
  5131.                                                + currentRead->bytesDone;
  5132.                                 }
  5133.                                
  5134.                                 // Read data into buffer
  5135.                                
  5136.                                 CFIndex result = CFReadStreamRead(readStream, buffer, (CFIndex)bytesToRead);
  5137.                                 LogVerbose(@"CFReadStreamRead(): result = %i", (int)result);
  5138.                                
  5139.                                 if (result < 0)
  5140.                                 {
  5141.                                         error = (__bridge_transfer NSError *)CFReadStreamCopyError(readStream);
  5142.                                 }
  5143.                                 else if (result == 0)
  5144.                                 {
  5145.                                         socketEOF = YES;
  5146.                                 }
  5147.                                 else
  5148.                                 {
  5149.                                         waiting = YES;
  5150.                                         bytesRead = (size_t)result;
  5151.                                 }
  5152.                                
  5153.                                 // We only know how many decrypted bytes were read.
  5154.                                 // The actual number of bytes read was likely more due to the overhead of the encryption.
  5155.                                 // So we reset our flag, and rely on the next callback to alert us of more data.
  5156.                                 flags &= ~kSecureSocketHasBytesAvailable;
  5157.                                
  5158.                                 #endif
  5159.                         }
  5160.                         else
  5161.                         {
  5162.                                 // Using SecureTransport for TLS
  5163.                                 //
  5164.                                 // We know:
  5165.                                 // - how many bytes are available on the socket
  5166.                                 // - how many encrypted bytes are sitting in the sslPreBuffer
  5167.                                 // - how many decypted bytes are sitting in the sslContext
  5168.                                 //
  5169.                                 // But we do NOT know:
  5170.                                 // - how many encypted bytes are sitting in the sslContext
  5171.                                 //
  5172.                                 // So we play the regular game of using an upper bound instead.
  5173.                                
  5174.                                 NSUInteger defaultReadLength = (1024 * 32);
  5175.                                
  5176.                                 if (defaultReadLength < estimatedBytesAvailable) {
  5177.                                         defaultReadLength = estimatedBytesAvailable + (1024 * 16);
  5178.                                 }
  5179.                                
  5180.                                 NSUInteger bytesToRead = [currentRead optimalReadLengthWithDefault:defaultReadLength
  5181.                                                                                    shouldPreBuffer:&readIntoPreBuffer];
  5182.                                
  5183.                                 if (bytesToRead > SIZE_MAX) { // NSUInteger may be bigger than size_t
  5184.                                         bytesToRead = SIZE_MAX;
  5185.                                 }
  5186.                                
  5187.                                 // Make sure we have enough room in the buffer for our read.
  5188.                                 //
  5189.                                 // We are either reading directly into the currentRead->buffer,
  5190.                                 // or we're reading into the temporary preBuffer.
  5191.                                
  5192.                                 if (readIntoPreBuffer)
  5193.                                 {
  5194.                                         [preBuffer ensureCapacityForWrite:bytesToRead];
  5195.                                        
  5196.                                         buffer = [preBuffer writeBuffer];
  5197.                                 }
  5198.                                 else
  5199.                                 {
  5200.                                         [currentRead ensureCapacityForAdditionalDataOfLength:bytesToRead];
  5201.                                        
  5202.                                         buffer = (uint8_t *)[currentRead->buffer mutableBytes]
  5203.                                                + currentRead->startOffset
  5204.                                                + currentRead->bytesDone;
  5205.                                 }
  5206.                                
  5207.                                 // The documentation from Apple states:
  5208.                                 //
  5209.                                 //     "a read operation might return errSSLWouldBlock,
  5210.                                 //      indicating that less data than requested was actually transferred"
  5211.                                 //
  5212.                                 // However, starting around 10.7, the function will sometimes return noErr,
  5213.                                 // even if it didn't read as much data as requested. So we need to watch out for that.
  5214.                                
  5215.                                 OSStatus result;
  5216.                                 do
  5217.                                 {
  5218.                                         void *loop_buffer = buffer + bytesRead;
  5219.                                         size_t loop_bytesToRead = (size_t)bytesToRead - bytesRead;
  5220.                                         size_t loop_bytesRead = 0;
  5221.                                        
  5222.                                         result = SSLRead(sslContext, loop_buffer, loop_bytesToRead, &loop_bytesRead);
  5223.                                         LogVerbose(@"read from secure socket = %u", (unsigned)loop_bytesRead);
  5224.                                        
  5225.                                         bytesRead += loop_bytesRead;
  5226.                                        
  5227.                                 } while ((result == noErr) && (bytesRead < bytesToRead));
  5228.                                
  5229.                                
  5230.                                 if (result != noErr)
  5231.                                 {
  5232.                                         if (result == errSSLWouldBlock)
  5233.                                                 waiting = YES;
  5234.                                         else
  5235.                                         {
  5236.                                                 if (result == errSSLClosedGraceful || result == errSSLClosedAbort)
  5237.                                                 {
  5238.                                                         // We've reached the end of the stream.
  5239.                                                         // Handle this the same way we would an EOF from the socket.
  5240.                                                         socketEOF = YES;
  5241.                                                         sslErrCode = result;
  5242.                                                 }
  5243.                                                 else
  5244.                                                 {
  5245.                                                         error = [self sslError:result];
  5246.                                                 }
  5247.                                         }
  5248.                                         // It's possible that bytesRead > 0, even if the result was errSSLWouldBlock.
  5249.                                         // This happens when the SSLRead function is able to read some data,
  5250.                                         // but not the entire amount we requested.
  5251.                                        
  5252.                                         if (bytesRead <= 0)
  5253.                                         {
  5254.                                                 bytesRead = 0;
  5255.                                         }
  5256.                                 }
  5257.                                
  5258.                                 // Do not modify socketFDBytesAvailable.
  5259.                                 // It will be updated via the SSLReadFunction().
  5260.                         }
  5261.                 }
  5262.                 else
  5263.                 {
  5264.                         // Normal socket operation
  5265.                        
  5266.                         NSUInteger bytesToRead;
  5267.                        
  5268.                         // There are 3 types of read packets:
  5269.                         //
  5270.                         // 1) Read all available data.
  5271.                         // 2) Read a specific length of data.
  5272.                         // 3) Read up to a particular terminator.
  5273.                        
  5274.                         if (currentRead->term != nil)
  5275.                         {
  5276.                                 // Read type #3 - read up to a terminator
  5277.                                
  5278.                                 bytesToRead = [currentRead readLengthForTermWithHint:estimatedBytesAvailable
  5279.                                                                      shouldPreBuffer:&readIntoPreBuffer];
  5280.                         }
  5281.                         else
  5282.                         {
  5283.                                 // Read type #1 or #2
  5284.                                
  5285.                                 bytesToRead = [currentRead readLengthForNonTermWithHint:estimatedBytesAvailable];
  5286.                         }
  5287.                        
  5288.                         if (bytesToRead > SIZE_MAX) { // NSUInteger may be bigger than size_t (read param 3)
  5289.                                 bytesToRead = SIZE_MAX;
  5290.                         }
  5291.                        
  5292.                         // Make sure we have enough room in the buffer for our read.
  5293.                         //
  5294.                         // We are either reading directly into the currentRead->buffer,
  5295.                         // or we're reading into the temporary preBuffer.
  5296.                        
  5297.                         if (readIntoPreBuffer)
  5298.                         {
  5299.                                 [preBuffer ensureCapacityForWrite:bytesToRead];
  5300.                                
  5301.                                 buffer = [preBuffer writeBuffer];
  5302.                         }
  5303.                         else
  5304.                         {
  5305.                                 [currentRead ensureCapacityForAdditionalDataOfLength:bytesToRead];
  5306.                                
  5307.                                 buffer = (uint8_t *)[currentRead->buffer mutableBytes]
  5308.                                        + currentRead->startOffset
  5309.                                        + currentRead->bytesDone;
  5310.                         }
  5311.                        
  5312.                         // Read data into buffer
  5313.                        
  5314.                         int socketFD = (socket4FD != SOCKET_NULL) ? socket4FD : (socket6FD != SOCKET_NULL) ? socket6FD : socketUN;
  5315.                        
  5316.                         ssize_t result = read(socketFD, buffer, (size_t)bytesToRead);
  5317.                         LogVerbose(@"read from socket = %i", (int)result);
  5318.                        
  5319.                         if (result < 0)
  5320.                         {
  5321.                                 if (errno == EWOULDBLOCK)
  5322.                                         waiting = YES;
  5323.                                 else
  5324.                                         error = [self errorWithErrno:errno reason:@"Error in read() function"];
  5325.                                
  5326.                                 socketFDBytesAvailable = 0;
  5327.                         }
  5328.                         else if (result == 0)
  5329.                         {
  5330.                                 socketEOF = YES;
  5331.                                 socketFDBytesAvailable = 0;
  5332.                         }
  5333.                         else
  5334.                         {
  5335.                                 bytesRead = result;
  5336.                                
  5337.                                 if (bytesRead < bytesToRead)
  5338.                                 {
  5339.                                         // The read returned less data than requested.
  5340.                                         // This means socketFDBytesAvailable was a bit off due to timing,
  5341.                                         // because we read from the socket right when the readSource event was firing.
  5342.                                         socketFDBytesAvailable = 0;
  5343.                                 }
  5344.                                 else
  5345.                                 {
  5346.                                         if (socketFDBytesAvailable <= bytesRead)
  5347.                                                 socketFDBytesAvailable = 0;
  5348.                                         else
  5349.                                                 socketFDBytesAvailable -= bytesRead;
  5350.                                 }
  5351.                                
  5352.                                 if (socketFDBytesAvailable == 0)
  5353.                                 {
  5354.                                         waiting = YES;
  5355.                                 }
  5356.                         }
  5357.                 }
  5358.                
  5359.                 if (bytesRead > 0)
  5360.                 {
  5361.                         // Check to see if the read operation is done
  5362.                        
  5363.                         if (currentRead->readLength > 0)
  5364.                         {
  5365.                                 // Read type #2 - read a specific length of data
  5366.                                 //
  5367.                                 // Note: We should never be using a prebuffer when we're reading a specific length of data.
  5368.                                
  5369.                                 NSAssert(readIntoPreBuffer == NO, @"Invalid logic");
  5370.                                
  5371.                                 currentRead->bytesDone += bytesRead;
  5372.                                 totalBytesReadForCurrentRead += bytesRead;
  5373.                                
  5374.                                 done = (currentRead->bytesDone == currentRead->readLength);
  5375.                         }
  5376.                         else if (currentRead->term != nil)
  5377.                         {
  5378.                                 // Read type #3 - read up to a terminator
  5379.                                
  5380.                                 if (readIntoPreBuffer)
  5381.                                 {
  5382.                                         // We just read a big chunk of data into the preBuffer
  5383.                                        
  5384.                                         [preBuffer didWrite:bytesRead];
  5385.                                         LogVerbose(@"read data into preBuffer - preBuffer.length = %zu", [preBuffer availableBytes]);
  5386.                                        
  5387.                                         // Search for the terminating sequence
  5388.                                        
  5389.                                         NSUInteger bytesToCopy = [currentRead readLengthForTermWithPreBuffer:preBuffer found:&done];
  5390.                                         LogVerbose(@"copying %lu bytes from preBuffer", (unsigned long)bytesToCopy);
  5391.                                        
  5392.                                         // Ensure there's room on the read packet's buffer
  5393.                                        
  5394.                                         [currentRead ensureCapacityForAdditionalDataOfLength:bytesToCopy];
  5395.                                        
  5396.                                         // Copy bytes from prebuffer into read buffer
  5397.                                        
  5398.                                         uint8_t *readBuf = (uint8_t *)[currentRead->buffer mutableBytes] + currentRead->startOffset
  5399.                                                                                                          + currentRead->bytesDone;
  5400.                                        
  5401.                                         memcpy(readBuf, [preBuffer readBuffer], bytesToCopy);
  5402.                                        
  5403.                                         // Remove the copied bytes from the prebuffer
  5404.                                         [preBuffer didRead:bytesToCopy];
  5405.                                         LogVerbose(@"preBuffer.length = %zu", [preBuffer availableBytes]);
  5406.                                        
  5407.                                         // Update totals
  5408.                                         currentRead->bytesDone += bytesToCopy;
  5409.                                         totalBytesReadForCurrentRead += bytesToCopy;
  5410.                                        
  5411.                                         // Our 'done' variable was updated via the readLengthForTermWithPreBuffer:found: method above
  5412.                                 }
  5413.                                 else
  5414.                                 {
  5415.                                         // We just read a big chunk of data directly into the packet's buffer.
  5416.                                         // We need to move any overflow into the prebuffer.
  5417.                                        
  5418.                                         NSInteger overflow = [currentRead searchForTermAfterPreBuffering:bytesRead];
  5419.                                        
  5420.                                         if (overflow == 0)
  5421.                                         {
  5422.                                                 // Perfect match!
  5423.                                                 // Every byte we read stays in the read buffer,
  5424.                                                 // and the last byte we read was the last byte of the term.
  5425.                                                
  5426.                                                 currentRead->bytesDone += bytesRead;
  5427.                                                 totalBytesReadForCurrentRead += bytesRead;
  5428.                                                 done = YES;
  5429.                                         }
  5430.                                         else if (overflow > 0)
  5431.                                         {
  5432.                                                 // The term was found within the data that we read,
  5433.                                                 // and there are extra bytes that extend past the end of the term.
  5434.                                                 // We need to move these excess bytes out of the read packet and into the prebuffer.
  5435.                                                
  5436.                                                 NSInteger underflow = bytesRead - overflow;
  5437.                                                
  5438.                                                 // Copy excess data into preBuffer
  5439.                                                
  5440.                                                 LogVerbose(@"copying %ld overflow bytes into preBuffer", (long)overflow);
  5441.                                                 [preBuffer ensureCapacityForWrite:overflow];
  5442.                                                
  5443.                                                 uint8_t *overflowBuffer = buffer + underflow;
  5444.                                                 memcpy([preBuffer writeBuffer], overflowBuffer, overflow);
  5445.                                                
  5446.                                                 [preBuffer didWrite:overflow];
  5447.                                                 LogVerbose(@"preBuffer.length = %zu", [preBuffer availableBytes]);
  5448.                                                
  5449.                                                 // Note: The completeCurrentRead method will trim the buffer for us.
  5450.                                                
  5451.                                                 currentRead->bytesDone += underflow;
  5452.                                                 totalBytesReadForCurrentRead += underflow;
  5453.                                                 done = YES;
  5454.                                         }
  5455.                                         else
  5456.                                         {
  5457.                                                 // The term was not found within the data that we read.
  5458.                                                
  5459.                                                 currentRead->bytesDone += bytesRead;
  5460.                                                 totalBytesReadForCurrentRead += bytesRead;
  5461.                                                 done = NO;
  5462.                                         }
  5463.                                 }
  5464.                                
  5465.                                 if (!done && currentRead->maxLength > 0)
  5466.                                 {
  5467.                                         // We're not done and there's a set maxLength.
  5468.                                         // Have we reached that maxLength yet?
  5469.                                        
  5470.                                         if (currentRead->bytesDone >= currentRead->maxLength)
  5471.                                         {
  5472.                                                 error = [self readMaxedOutError];
  5473.                                         }
  5474.                                 }
  5475.                         }
  5476.                         else
  5477.                         {
  5478.                                 // Read type #1 - read all available data
  5479.                                
  5480.                                 if (readIntoPreBuffer)
  5481.                                 {
  5482.                                         // We just read a chunk of data into the preBuffer
  5483.                                        
  5484.                                         [preBuffer didWrite:bytesRead];
  5485.                                        
  5486.                                         // Now copy the data into the read packet.
  5487.                                         //
  5488.                                         // Recall that we didn't read directly into the packet's buffer to avoid
  5489.                                         // over-allocating memory since we had no clue how much data was available to be read.
  5490.                                         //
  5491.                                         // Ensure there's room on the read packet's buffer
  5492.                                        
  5493.                                         [currentRead ensureCapacityForAdditionalDataOfLength:bytesRead];
  5494.                                        
  5495.                                         // Copy bytes from prebuffer into read buffer
  5496.                                        
  5497.                                         uint8_t *readBuf = (uint8_t *)[currentRead->buffer mutableBytes] + currentRead->startOffset
  5498.                                                                                                          + currentRead->bytesDone;
  5499.                                        
  5500.                                         memcpy(readBuf, [preBuffer readBuffer], bytesRead);
  5501.                                        
  5502.                                         // Remove the copied bytes from the prebuffer
  5503.                                         [preBuffer didRead:bytesRead];
  5504.                                        
  5505.                                         // Update totals
  5506.                                         currentRead->bytesDone += bytesRead;
  5507.                                         totalBytesReadForCurrentRead += bytesRead;
  5508.                                 }
  5509.                                 else
  5510.                                 {
  5511.                                         currentRead->bytesDone += bytesRead;
  5512.                                         totalBytesReadForCurrentRead += bytesRead;
  5513.                                 }
  5514.                                
  5515.                                 done = YES;
  5516.                         }
  5517.                        
  5518.                 } // if (bytesRead > 0)
  5519.                
  5520.         } // if (!done && !error && !socketEOF && hasBytesAvailable)
  5521.        
  5522.        
  5523.         if (!done && currentRead->readLength == 0 && currentRead->term == nil)
  5524.         {
  5525.                 // Read type #1 - read all available data
  5526.                 //
  5527.                 // We might arrive here if we read data from the prebuffer but not from the socket.
  5528.                
  5529.                 done = (totalBytesReadForCurrentRead > 0);
  5530.         }
  5531.        
  5532.         // Check to see if we're done, or if we've made progress
  5533.        
  5534.         if (done)
  5535.         {
  5536.                 [self completeCurrentRead];
  5537.                
  5538.                 if (!error && (!socketEOF || [preBuffer availableBytes] > 0))
  5539.                 {
  5540.                         [self maybeDequeueRead];
  5541.                 }
  5542.         }
  5543.         else if (totalBytesReadForCurrentRead > 0)
  5544.         {
  5545.                 // We're not done read type #2 or #3 yet, but we have read in some bytes
  5546.                 //
  5547.                 // We ensure that `waiting` is set in order to resume the readSource (if it is suspended). It is
  5548.                 // possible to reach this point and `waiting` not be set, if the current read's length is
  5549.                 // sufficiently large. In that case, we may have read to some upperbound successfully, but
  5550.                 // that upperbound could be smaller than the desired length.
  5551.                 waiting = YES;
  5552.  
  5553.                 __strong id<GCDAsyncSocketDelegate> theDelegate = delegate;
  5554.                
  5555.                 if (delegateQueue && [theDelegate respondsToSelector:@selector(socket:didReadPartialDataOfLength:tag:)])
  5556.                 {
  5557.                         long theReadTag = currentRead->tag;
  5558.                        
  5559.                         dispatch_async(delegateQueue, ^{ @autoreleasepool {
  5560.                                
  5561.                                 [theDelegate socket:self didReadPartialDataOfLength:totalBytesReadForCurrentRead tag:theReadTag];
  5562.                         }});
  5563.                 }
  5564.         }
  5565.        
  5566.         // Check for errors
  5567.        
  5568.         if (error)
  5569.         {
  5570.                 [self closeWithError:error];
  5571.         }
  5572.         else if (socketEOF)
  5573.         {
  5574.                 [self doReadEOF];
  5575.         }
  5576.         else if (waiting)
  5577.         {
  5578.                 if (![self usingCFStreamForTLS])
  5579.                 {
  5580.                         // Monitor the socket for readability (if we're not already doing so)
  5581.                         [self resumeReadSource];
  5582.                 }
  5583.         }
  5584.        
  5585.         // Do not add any code here without first adding return statements in the error cases above.
  5586. }
  5587.  
  5588. - (void)doReadEOF
  5589. {
  5590.         LogTrace();
  5591.        
  5592.         // This method may be called more than once.
  5593.         // If the EOF is read while there is still data in the preBuffer,
  5594.         // then this method may be called continually after invocations of doReadData to see if it's time to disconnect.
  5595.        
  5596.         flags |= kSocketHasReadEOF;
  5597.        
  5598.         if (flags & kSocketSecure)
  5599.         {
  5600.                 // If the SSL layer has any buffered data, flush it into the preBuffer now.
  5601.                
  5602.                 [self flushSSLBuffers];
  5603.         }
  5604.        
  5605.         BOOL shouldDisconnect = NO;
  5606.         NSError *error = nil;
  5607.        
  5608.         if ((flags & kStartingReadTLS) || (flags & kStartingWriteTLS))
  5609.         {
  5610.                 // We received an EOF during or prior to startTLS.
  5611.                 // The SSL/TLS handshake is now impossible, so this is an unrecoverable situation.
  5612.                
  5613.                 shouldDisconnect = YES;
  5614.                
  5615.                 if ([self usingSecureTransportForTLS])
  5616.                 {
  5617.                         error = [self sslError:errSSLClosedAbort];
  5618.                 }
  5619.         }
  5620.         else if (flags & kReadStreamClosed)
  5621.         {
  5622.                 // The preBuffer has already been drained.
  5623.                 // The config allows half-duplex connections.
  5624.                 // We've previously checked the socket, and it appeared writeable.
  5625.                 // So we marked the read stream as closed and notified the delegate.
  5626.                 //
  5627.                 // As per the half-duplex contract, the socket will be closed when a write fails,
  5628.                 // or when the socket is manually closed.
  5629.                
  5630.                 shouldDisconnect = NO;
  5631.         }
  5632.         else if ([preBuffer availableBytes] > 0)
  5633.         {
  5634.                 LogVerbose(@"Socket reached EOF, but there is still data available in prebuffer");
  5635.                
  5636.                 // Although we won't be able to read any more data from the socket,
  5637.                 // there is existing data that has been prebuffered that we can read.
  5638.                
  5639.                 shouldDisconnect = NO;
  5640.         }
  5641.         else if (config & kAllowHalfDuplexConnection)
  5642.         {
  5643.                 // We just received an EOF (end of file) from the socket's read stream.
  5644.                 // This means the remote end of the socket (the peer we're connected to)
  5645.                 // has explicitly stated that it will not be sending us any more data.
  5646.                 //
  5647.                 // Query the socket to see if it is still writeable. (Perhaps the peer will continue reading data from us)
  5648.                
  5649.                 int socketFD = (socket4FD != SOCKET_NULL) ? socket4FD : (socket6FD != SOCKET_NULL) ? socket6FD : socketUN;
  5650.                
  5651.                 struct pollfd pfd[1];
  5652.                 pfd[0].fd = socketFD;
  5653.                 pfd[0].events = POLLOUT;
  5654.                 pfd[0].revents = 0;
  5655.                
  5656.                 poll(pfd, 1, 0);
  5657.                
  5658.                 if (pfd[0].revents & POLLOUT)
  5659.                 {
  5660.                         // Socket appears to still be writeable
  5661.                        
  5662.                         shouldDisconnect = NO;
  5663.                         flags |= kReadStreamClosed;
  5664.                        
  5665.                         // Notify the delegate that we're going half-duplex
  5666.                        
  5667.                         __strong id<GCDAsyncSocketDelegate> theDelegate = delegate;
  5668.  
  5669.                         if (delegateQueue && [theDelegate respondsToSelector:@selector(socketDidCloseReadStream:)])
  5670.                         {
  5671.                                 dispatch_async(delegateQueue, ^{ @autoreleasepool {
  5672.                                        
  5673.                                         [theDelegate socketDidCloseReadStream:self];
  5674.                                 }});
  5675.                         }
  5676.                 }
  5677.                 else
  5678.                 {
  5679.                         shouldDisconnect = YES;
  5680.                 }
  5681.         }
  5682.         else
  5683.         {
  5684.                 shouldDisconnect = YES;
  5685.         }
  5686.        
  5687.        
  5688.         if (shouldDisconnect)
  5689.         {
  5690.                 if (error == nil)
  5691.                 {
  5692.                         if ([self usingSecureTransportForTLS])
  5693.                         {
  5694.                                 if (sslErrCode != noErr && sslErrCode != errSSLClosedGraceful)
  5695.                                 {
  5696.                                         error = [self sslError:sslErrCode];
  5697.                                 }
  5698.                                 else
  5699.                                 {
  5700.                                         error = [self connectionClosedError];
  5701.                                 }
  5702.                         }
  5703.                         else
  5704.                         {
  5705.                                 error = [self connectionClosedError];
  5706.                         }
  5707.                 }
  5708.                 [self closeWithError:error];
  5709.         }
  5710.         else
  5711.         {
  5712.                 if (![self usingCFStreamForTLS])
  5713.                 {
  5714.                         // Suspend the read source (if needed)
  5715.                        
  5716.                         [self suspendReadSource];
  5717.                 }
  5718.         }
  5719. }
  5720.  
  5721. - (void)completeCurrentRead
  5722. {
  5723.         LogTrace();
  5724.        
  5725.         NSAssert(currentRead, @"Trying to complete current read when there is no current read.");
  5726.        
  5727.        
  5728.         NSData *result = nil;
  5729.        
  5730.         if (currentRead->bufferOwner)
  5731.         {
  5732.                 // We created the buffer on behalf of the user.
  5733.                 // Trim our buffer to be the proper size.
  5734.                 [currentRead->buffer setLength:currentRead->bytesDone];
  5735.                
  5736.                 result = currentRead->buffer;
  5737.         }
  5738.         else
  5739.         {
  5740.                 // We did NOT create the buffer.
  5741.                 // The buffer is owned by the caller.
  5742.                 // Only trim the buffer if we had to increase its size.
  5743.                
  5744.                 if ([currentRead->buffer length] > currentRead->originalBufferLength)
  5745.                 {
  5746.                         NSUInteger readSize = currentRead->startOffset + currentRead->bytesDone;
  5747.                         NSUInteger origSize = currentRead->originalBufferLength;
  5748.                        
  5749.                         NSUInteger buffSize = MAX(readSize, origSize);
  5750.                        
  5751.                         [currentRead->buffer setLength:buffSize];
  5752.                 }
  5753.                
  5754.                 uint8_t *buffer = (uint8_t *)[currentRead->buffer mutableBytes] + currentRead->startOffset;
  5755.                
  5756.                 result = [NSData dataWithBytesNoCopy:buffer length:currentRead->bytesDone freeWhenDone:NO];
  5757.         }
  5758.        
  5759.         __strong id<GCDAsyncSocketDelegate> theDelegate = delegate;
  5760.  
  5761.         if (delegateQueue && [theDelegate respondsToSelector:@selector(socket:didReadData:withTag:)])
  5762.         {
  5763.                 GCDAsyncReadPacket *theRead = currentRead; // Ensure currentRead retained since result may not own buffer
  5764.                
  5765.                 dispatch_async(delegateQueue, ^{ @autoreleasepool {
  5766.                        
  5767.                         [theDelegate socket:self didReadData:result withTag:theRead->tag];
  5768.                 }});
  5769.         }
  5770.        
  5771.         [self endCurrentRead];
  5772. }
  5773.  
  5774. - (void)endCurrentRead
  5775. {
  5776.         if (readTimer)
  5777.         {
  5778.                 dispatch_source_cancel(readTimer);
  5779.                 readTimer = NULL;
  5780.         }
  5781.        
  5782.         currentRead = nil;
  5783. }
  5784.  
  5785. - (void)setupReadTimerWithTimeout:(NSTimeInterval)timeout
  5786. {
  5787.         if (timeout >= 0.0)
  5788.         {
  5789.                 readTimer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, socketQueue);
  5790.                
  5791.                 __weak GCDAsyncSocket *weakSelf = self;
  5792.                
  5793.                 dispatch_source_set_event_handler(readTimer, ^{ @autoreleasepool {
  5794.                 #pragma clang diagnostic push
  5795.                 #pragma clang diagnostic warning "-Wimplicit-retain-self"
  5796.                        
  5797.                         __strong GCDAsyncSocket *strongSelf = weakSelf;
  5798.                         if (strongSelf == nil) return_from_block;
  5799.                        
  5800.                         [strongSelf doReadTimeout];
  5801.                        
  5802.                 #pragma clang diagnostic pop
  5803.                 }});
  5804.                
  5805.                 #if !OS_OBJECT_USE_OBJC
  5806.                 dispatch_source_t theReadTimer = readTimer;
  5807.                 dispatch_source_set_cancel_handler(readTimer, ^{
  5808.                 #pragma clang diagnostic push
  5809.                 #pragma clang diagnostic warning "-Wimplicit-retain-self"
  5810.                        
  5811.                         LogVerbose(@"dispatch_release(readTimer)");
  5812.                         dispatch_release(theReadTimer);
  5813.                        
  5814.                 #pragma clang diagnostic pop
  5815.                 });
  5816.                 #endif
  5817.                
  5818.                 dispatch_time_t tt = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(timeout * NSEC_PER_SEC));
  5819.                
  5820.                 dispatch_source_set_timer(readTimer, tt, DISPATCH_TIME_FOREVER, 0);
  5821.                 dispatch_resume(readTimer);
  5822.         }
  5823. }
  5824.  
  5825. - (void)doReadTimeout
  5826. {
  5827.         // This is a little bit tricky.
  5828.         // Ideally we'd like to synchronously query the delegate about a timeout extension.
  5829.         // But if we do so synchronously we risk a possible deadlock.
  5830.         // So instead we have to do so asynchronously, and callback to ourselves from within the delegate block.
  5831.        
  5832.         flags |= kReadsPaused;
  5833.        
  5834.         __strong id<GCDAsyncSocketDelegate> theDelegate = delegate;
  5835.  
  5836.         if (delegateQueue && [theDelegate respondsToSelector:@selector(socket:shouldTimeoutReadWithTag:elapsed:bytesDone:)])
  5837.         {
  5838.                 GCDAsyncReadPacket *theRead = currentRead;
  5839.                
  5840.                 dispatch_async(delegateQueue, ^{ @autoreleasepool {
  5841.                        
  5842.                         NSTimeInterval timeoutExtension = 0.0;
  5843.                        
  5844.                         timeoutExtension = [theDelegate socket:self shouldTimeoutReadWithTag:theRead->tag
  5845.                                                                                      elapsed:theRead->timeout
  5846.                                                                                    bytesDone:theRead->bytesDone];
  5847.                        
  5848.             dispatch_async(self->socketQueue, ^{ @autoreleasepool {
  5849.                                
  5850.                                 [self doReadTimeoutWithExtension:timeoutExtension];
  5851.                         }});
  5852.                 }});
  5853.         }
  5854.         else
  5855.         {
  5856.                 [self doReadTimeoutWithExtension:0.0];
  5857.         }
  5858. }
  5859.  
  5860. - (void)doReadTimeoutWithExtension:(NSTimeInterval)timeoutExtension
  5861. {
  5862.         if (currentRead)
  5863.         {
  5864.                 if (timeoutExtension > 0.0)
  5865.                 {
  5866.                         currentRead->timeout += timeoutExtension;
  5867.                        
  5868.                         // Reschedule the timer
  5869.                         dispatch_time_t tt = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(timeoutExtension * NSEC_PER_SEC));
  5870.                         dispatch_source_set_timer(readTimer, tt, DISPATCH_TIME_FOREVER, 0);
  5871.                        
  5872.                         // Unpause reads, and continue
  5873.                         flags &= ~kReadsPaused;
  5874.                         [self doReadData];
  5875.                 }
  5876.                 else
  5877.                 {
  5878.                         LogVerbose(@"ReadTimeout");
  5879.                        
  5880.                         [self closeWithError:[self readTimeoutError]];
  5881.                 }
  5882.         }
  5883. }
  5884.  
  5885. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  5886. #pragma mark Writing
  5887. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  5888.  
  5889. - (void)writeData:(NSData *)data withTimeout:(NSTimeInterval)timeout tag:(long)tag
  5890. {
  5891.         if ([data length] == 0) return;
  5892.        
  5893.         GCDAsyncWritePacket *packet = [[GCDAsyncWritePacket alloc] initWithData:data timeout:timeout tag:tag];
  5894.        
  5895.         dispatch_async(socketQueue, ^{ @autoreleasepool {
  5896.                
  5897.                 LogTrace();
  5898.                
  5899.         if ((self->flags & kSocketStarted) && !(self->flags & kForbidReadsWrites))
  5900.                 {
  5901.             [self->writeQueue addObject:packet];
  5902.                         [self maybeDequeueWrite];
  5903.                 }
  5904.         }});
  5905.        
  5906.         // Do not rely on the block being run in order to release the packet,
  5907.         // as the queue might get released without the block completing.
  5908. }
  5909.  
  5910. - (float)progressOfWriteReturningTag:(long *)tagPtr bytesDone:(NSUInteger *)donePtr total:(NSUInteger *)totalPtr
  5911. {
  5912.         __block float result = 0.0F;
  5913.        
  5914.         dispatch_block_t block = ^{
  5915.                
  5916.         if (!self->currentWrite || ![self->currentWrite isKindOfClass:[GCDAsyncWritePacket class]])
  5917.                 {
  5918.                         // We're not writing anything right now.
  5919.                        
  5920.                         if (tagPtr != NULL)   *tagPtr = 0;
  5921.                         if (donePtr != NULL)  *donePtr = 0;
  5922.                         if (totalPtr != NULL) *totalPtr = 0;
  5923.                        
  5924.                         result = NAN;
  5925.                 }
  5926.                 else
  5927.                 {
  5928.             NSUInteger done = self->currentWrite->bytesDone;
  5929.             NSUInteger total = [self->currentWrite->buffer length];
  5930.                        
  5931.             if (tagPtr != NULL)   *tagPtr = self->currentWrite->tag;
  5932.                         if (donePtr != NULL)  *donePtr = done;
  5933.                         if (totalPtr != NULL) *totalPtr = total;
  5934.                        
  5935.                         result = (float)done / (float)total;
  5936.                 }
  5937.         };
  5938.        
  5939.         if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
  5940.                 block();
  5941.         else
  5942.                 dispatch_sync(socketQueue, block);
  5943.        
  5944.         return result;
  5945. }
  5946.  
  5947. /**
  5948.  * Conditionally starts a new write.
  5949.  *
  5950.  * It is called when:
  5951.  * - a user requests a write
  5952.  * - after a write request has finished (to handle the next request)
  5953.  * - immediately after the socket opens to handle any pending requests
  5954.  *
  5955.  * This method also handles auto-disconnect post read/write completion.
  5956. **/
  5957. - (void)maybeDequeueWrite
  5958. {
  5959.         LogTrace();
  5960.         NSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @"Must be dispatched on socketQueue");
  5961.        
  5962.        
  5963.         // If we're not currently processing a write AND we have an available write stream
  5964.         if ((currentWrite == nil) && (flags & kConnected))
  5965.         {
  5966.                 if ([writeQueue count] > 0)
  5967.                 {
  5968.                         // Dequeue the next object in the write queue
  5969.                         currentWrite = [writeQueue objectAtIndex:0];
  5970.                         [writeQueue removeObjectAtIndex:0];
  5971.                        
  5972.                        
  5973.                         if ([currentWrite isKindOfClass:[GCDAsyncSpecialPacket class]])
  5974.                         {
  5975.                                 LogVerbose(@"Dequeued GCDAsyncSpecialPacket");
  5976.                                
  5977.                                 // Attempt to start TLS
  5978.                                 flags |= kStartingWriteTLS;
  5979.                                
  5980.                                 // This method won't do anything unless both kStartingReadTLS and kStartingWriteTLS are set
  5981.                                 [self maybeStartTLS];
  5982.                         }
  5983.                         else
  5984.                         {
  5985.                                 LogVerbose(@"Dequeued GCDAsyncWritePacket");
  5986.                                
  5987.                                 // Setup write timer (if needed)
  5988.                                 [self setupWriteTimerWithTimeout:currentWrite->timeout];
  5989.                                
  5990.                                 // Immediately write, if possible
  5991.                                 [self doWriteData];
  5992.                         }
  5993.                 }
  5994.                 else if (flags & kDisconnectAfterWrites)
  5995.                 {
  5996.                         if (flags & kDisconnectAfterReads)
  5997.                         {
  5998.                                 if (([readQueue count] == 0) && (currentRead == nil))
  5999.                                 {
  6000.                                         [self closeWithError:nil];
  6001.                                 }
  6002.                         }
  6003.                         else
  6004.                         {
  6005.                                 [self closeWithError:nil];
  6006.                         }
  6007.                 }
  6008.         }
  6009. }
  6010.  
  6011. - (void)doWriteData
  6012. {
  6013.         LogTrace();
  6014.        
  6015.         // This method is called by the writeSource via the socketQueue
  6016.        
  6017.         if ((currentWrite == nil) || (flags & kWritesPaused))
  6018.         {
  6019.                 LogVerbose(@"No currentWrite or kWritesPaused");
  6020.                
  6021.                 // Unable to write at this time
  6022.                
  6023.                 if ([self usingCFStreamForTLS])
  6024.                 {
  6025.                         // CFWriteStream only fires once when there is available data.
  6026.                         // It won't fire again until we've invoked CFWriteStreamWrite.
  6027.                 }
  6028.                 else
  6029.                 {
  6030.                         // If the writeSource is firing, we need to pause it
  6031.                         // or else it will continue to fire over and over again.
  6032.                        
  6033.                         if (flags & kSocketCanAcceptBytes)
  6034.                         {
  6035.                                 [self suspendWriteSource];
  6036.                         }
  6037.                 }
  6038.                 return;
  6039.         }
  6040.        
  6041.         if (!(flags & kSocketCanAcceptBytes))
  6042.         {
  6043.                 LogVerbose(@"No space available to write...");
  6044.                
  6045.                 // No space available to write.
  6046.                
  6047.                 if (![self usingCFStreamForTLS])
  6048.                 {
  6049.                         // Need to wait for writeSource to fire and notify us of
  6050.                         // available space in the socket's internal write buffer.
  6051.                        
  6052.                         [self resumeWriteSource];
  6053.                 }
  6054.                 return;
  6055.         }
  6056.        
  6057.         if (flags & kStartingWriteTLS)
  6058.         {
  6059.                 LogVerbose(@"Waiting for SSL/TLS handshake to complete");
  6060.                
  6061.                 // The writeQueue is waiting for SSL/TLS handshake to complete.
  6062.                
  6063.                 if (flags & kStartingReadTLS)
  6064.                 {
  6065.                         if ([self usingSecureTransportForTLS] && lastSSLHandshakeError == errSSLWouldBlock)
  6066.                         {
  6067.                                 // We are in the process of a SSL Handshake.
  6068.                                 // We were waiting for available space in the socket's internal OS buffer to continue writing.
  6069.                        
  6070.                                 [self ssl_continueSSLHandshake];
  6071.                         }
  6072.                 }
  6073.                 else
  6074.                 {
  6075.                         // We are still waiting for the readQueue to drain and start the SSL/TLS process.
  6076.                         // We now know we can write to the socket.
  6077.                        
  6078.                         if (![self usingCFStreamForTLS])
  6079.                         {
  6080.                                 // Suspend the write source or else it will continue to fire nonstop.
  6081.                                
  6082.                                 [self suspendWriteSource];
  6083.                         }
  6084.                 }
  6085.                
  6086.                 return;
  6087.         }
  6088.        
  6089.         // Note: This method is not called if currentWrite is a GCDAsyncSpecialPacket (startTLS packet)
  6090.        
  6091.         BOOL waiting = NO;
  6092.         NSError *error = nil;
  6093.         size_t bytesWritten = 0;
  6094.        
  6095.         if (flags & kSocketSecure)
  6096.         {
  6097.                 if ([self usingCFStreamForTLS])
  6098.                 {
  6099.                         #if TARGET_OS_IPHONE
  6100.                        
  6101.                         //
  6102.                         // Writing data using CFStream (over internal TLS)
  6103.                         //
  6104.                        
  6105.                         const uint8_t *buffer = (const uint8_t *)[currentWrite->buffer bytes] + currentWrite->bytesDone;
  6106.                        
  6107.                         NSUInteger bytesToWrite = [currentWrite->buffer length] - currentWrite->bytesDone;
  6108.                        
  6109.                         if (bytesToWrite > SIZE_MAX) // NSUInteger may be bigger than size_t (write param 3)
  6110.                         {
  6111.                                 bytesToWrite = SIZE_MAX;
  6112.                         }
  6113.                
  6114.                         CFIndex result = CFWriteStreamWrite(writeStream, buffer, (CFIndex)bytesToWrite);
  6115.                         LogVerbose(@"CFWriteStreamWrite(%lu) = %li", (unsigned long)bytesToWrite, result);
  6116.                
  6117.                         if (result < 0)
  6118.                         {
  6119.                                 error = (__bridge_transfer NSError *)CFWriteStreamCopyError(writeStream);
  6120.                         }
  6121.                         else
  6122.                         {
  6123.                                 bytesWritten = (size_t)result;
  6124.                                
  6125.                                 // We always set waiting to true in this scenario.
  6126.                                 // CFStream may have altered our underlying socket to non-blocking.
  6127.                                 // Thus if we attempt to write without a callback, we may end up blocking our queue.
  6128.                                 waiting = YES;
  6129.                         }
  6130.                        
  6131.                         #endif
  6132.                 }
  6133.                 else
  6134.                 {
  6135.                         // We're going to use the SSLWrite function.
  6136.                         //
  6137.                         // OSStatus SSLWrite(SSLContextRef context, const void *data, size_t dataLength, size_t *processed)
  6138.                         //
  6139.                         // Parameters:
  6140.                         // context     - An SSL session context reference.
  6141.                         // data        - A pointer to the buffer of data to write.
  6142.                         // dataLength  - The amount, in bytes, of data to write.
  6143.                         // processed   - On return, the length, in bytes, of the data actually written.
  6144.                         //
  6145.                         // It sounds pretty straight-forward,
  6146.                         // but there are a few caveats you should be aware of.
  6147.                         //
  6148.                         // The SSLWrite method operates in a non-obvious (and rather annoying) manner.
  6149.                         // According to the documentation:
  6150.                         //
  6151.                         //   Because you may configure the underlying connection to operate in a non-blocking manner,
  6152.                         //   a write operation might return errSSLWouldBlock, indicating that less data than requested
  6153.                         //   was actually transferred. In this case, you should repeat the call to SSLWrite until some
  6154.                         //   other result is returned.
  6155.                         //
  6156.                         // This sounds perfect, but when our SSLWriteFunction returns errSSLWouldBlock,
  6157.                         // then the SSLWrite method returns (with the proper errSSLWouldBlock return value),
  6158.                         // but it sets processed to dataLength !!
  6159.                         //
  6160.                         // In other words, if the SSLWrite function doesn't completely write all the data we tell it to,
  6161.                         // then it doesn't tell us how many bytes were actually written. So, for example, if we tell it to
  6162.                         // write 256 bytes then it might actually write 128 bytes, but then report 0 bytes written.
  6163.                         //
  6164.                         // You might be wondering:
  6165.                         // If the SSLWrite function doesn't tell us how many bytes were written,
  6166.                         // then how in the world are we supposed to update our parameters (buffer & bytesToWrite)
  6167.                         // for the next time we invoke SSLWrite?
  6168.                         //
  6169.                         // The answer is that SSLWrite cached all the data we told it to write,
  6170.                         // and it will push out that data next time we call SSLWrite.
  6171.                         // If we call SSLWrite with new data, it will push out the cached data first, and then the new data.
  6172.                         // If we call SSLWrite with empty data, then it will simply push out the cached data.
  6173.                         //
  6174.                         // For this purpose we're going to break large writes into a series of smaller writes.
  6175.                         // This allows us to report progress back to the delegate.
  6176.                        
  6177.                         OSStatus result;
  6178.                        
  6179.                         BOOL hasCachedDataToWrite = (sslWriteCachedLength > 0);
  6180.                         BOOL hasNewDataToWrite = YES;
  6181.                        
  6182.                         if (hasCachedDataToWrite)
  6183.                         {
  6184.                                 size_t processed = 0;
  6185.                                
  6186.                                 result = SSLWrite(sslContext, NULL, 0, &processed);
  6187.                                
  6188.                                 if (result == noErr)
  6189.                                 {
  6190.                                         bytesWritten = sslWriteCachedLength;
  6191.                                         sslWriteCachedLength = 0;
  6192.                                        
  6193.                                         if ([currentWrite->buffer length] == (currentWrite->bytesDone + bytesWritten))
  6194.                                         {
  6195.                                                 // We've written all data for the current write.
  6196.                                                 hasNewDataToWrite = NO;
  6197.                                         }
  6198.                                 }
  6199.                                 else
  6200.                                 {
  6201.                                         if (result == errSSLWouldBlock)
  6202.                                         {
  6203.                                                 waiting = YES;
  6204.                                         }
  6205.                                         else
  6206.                                         {
  6207.                                                 error = [self sslError:result];
  6208.                                         }
  6209.                                        
  6210.                                         // Can't write any new data since we were unable to write the cached data.
  6211.                                         hasNewDataToWrite = NO;
  6212.                                 }
  6213.                         }
  6214.                        
  6215.                         if (hasNewDataToWrite)
  6216.                         {
  6217.                                 const uint8_t *buffer = (const uint8_t *)[currentWrite->buffer bytes]
  6218.                                                                         + currentWrite->bytesDone
  6219.                                                                         + bytesWritten;
  6220.                                
  6221.                                 NSUInteger bytesToWrite = [currentWrite->buffer length] - currentWrite->bytesDone - bytesWritten;
  6222.                                
  6223.                                 if (bytesToWrite > SIZE_MAX) // NSUInteger may be bigger than size_t (write param 3)
  6224.                                 {
  6225.                                         bytesToWrite = SIZE_MAX;
  6226.                                 }
  6227.                                
  6228.                                 size_t bytesRemaining = bytesToWrite;
  6229.                                
  6230.                                 BOOL keepLooping = YES;
  6231.                                 while (keepLooping)
  6232.                                 {
  6233.                                         const size_t sslMaxBytesToWrite = 32768;
  6234.                                         size_t sslBytesToWrite = MIN(bytesRemaining, sslMaxBytesToWrite);
  6235.                                         size_t sslBytesWritten = 0;
  6236.                                        
  6237.                                         result = SSLWrite(sslContext, buffer, sslBytesToWrite, &sslBytesWritten);
  6238.                                        
  6239.                                         if (result == noErr)
  6240.                                         {
  6241.                                                 buffer += sslBytesWritten;
  6242.                                                 bytesWritten += sslBytesWritten;
  6243.                                                 bytesRemaining -= sslBytesWritten;
  6244.                                                
  6245.                                                 keepLooping = (bytesRemaining > 0);
  6246.                                         }
  6247.                                         else
  6248.                                         {
  6249.                                                 if (result == errSSLWouldBlock)
  6250.                                                 {
  6251.                                                         waiting = YES;
  6252.                                                         sslWriteCachedLength = sslBytesToWrite;
  6253.                                                 }
  6254.                                                 else
  6255.                                                 {
  6256.                                                         error = [self sslError:result];
  6257.                                                 }
  6258.                                                
  6259.                                                 keepLooping = NO;
  6260.                                         }
  6261.                                        
  6262.                                 } // while (keepLooping)
  6263.                                
  6264.                         } // if (hasNewDataToWrite)
  6265.                 }
  6266.         }
  6267.         else
  6268.         {
  6269.                 //
  6270.                 // Writing data directly over raw socket
  6271.                 //
  6272.                
  6273.                 int socketFD = (socket4FD != SOCKET_NULL) ? socket4FD : (socket6FD != SOCKET_NULL) ? socket6FD : socketUN;
  6274.                
  6275.                 const uint8_t *buffer = (const uint8_t *)[currentWrite->buffer bytes] + currentWrite->bytesDone;
  6276.                
  6277.                 NSUInteger bytesToWrite = [currentWrite->buffer length] - currentWrite->bytesDone;
  6278.                
  6279.                 if (bytesToWrite > SIZE_MAX) // NSUInteger may be bigger than size_t (write param 3)
  6280.                 {
  6281.                         bytesToWrite = SIZE_MAX;
  6282.                 }
  6283.                
  6284.                 ssize_t result = write(socketFD, buffer, (size_t)bytesToWrite);
  6285.                 LogVerbose(@"wrote to socket = %zd", result);
  6286.                
  6287.                 // Check results
  6288.                 if (result < 0)
  6289.                 {
  6290.                         if (errno == EWOULDBLOCK)
  6291.                         {
  6292.                                 waiting = YES;
  6293.                         }
  6294.                         else
  6295.                         {
  6296.                                 error = [self errorWithErrno:errno reason:@"Error in write() function"];
  6297.                         }
  6298.                 }
  6299.                 else
  6300.                 {
  6301.                         bytesWritten = result;
  6302.                 }
  6303.         }
  6304.        
  6305.         // We're done with our writing.
  6306.         // If we explictly ran into a situation where the socket told us there was no room in the buffer,
  6307.         // then we immediately resume listening for notifications.
  6308.         //
  6309.         // We must do this before we dequeue another write,
  6310.         // as that may in turn invoke this method again.
  6311.         //
  6312.         // Note that if CFStream is involved, it may have maliciously put our socket in blocking mode.
  6313.        
  6314.         if (waiting)
  6315.         {
  6316.                 flags &= ~kSocketCanAcceptBytes;
  6317.                
  6318.                 if (![self usingCFStreamForTLS])
  6319.                 {
  6320.                         [self resumeWriteSource];
  6321.                 }
  6322.         }
  6323.        
  6324.         // Check our results
  6325.        
  6326.         BOOL done = NO;
  6327.        
  6328.         if (bytesWritten > 0)
  6329.         {
  6330.                 // Update total amount read for the current write
  6331.                 currentWrite->bytesDone += bytesWritten;
  6332.                 LogVerbose(@"currentWrite->bytesDone = %lu", (unsigned long)currentWrite->bytesDone);
  6333.                
  6334.                 // Is packet done?
  6335.                 done = (currentWrite->bytesDone == [currentWrite->buffer length]);
  6336.         }
  6337.        
  6338.         if (done)
  6339.         {
  6340.                 [self completeCurrentWrite];
  6341.                
  6342.                 if (!error)
  6343.                 {
  6344.                         dispatch_async(socketQueue, ^{ @autoreleasepool{
  6345.                                
  6346.                                 [self maybeDequeueWrite];
  6347.                         }});
  6348.                 }
  6349.         }
  6350.         else
  6351.         {
  6352.                 // We were unable to finish writing the data,
  6353.                 // so we're waiting for another callback to notify us of available space in the lower-level output buffer.
  6354.                
  6355.                 if (!waiting && !error)
  6356.                 {
  6357.                         // This would be the case if our write was able to accept some data, but not all of it.
  6358.                        
  6359.                         flags &= ~kSocketCanAcceptBytes;
  6360.                        
  6361.                         if (![self usingCFStreamForTLS])
  6362.                         {
  6363.                                 [self resumeWriteSource];
  6364.                         }
  6365.                 }
  6366.                
  6367.                 if (bytesWritten > 0)
  6368.                 {
  6369.                         // We're not done with the entire write, but we have written some bytes
  6370.                        
  6371.                         __strong id<GCDAsyncSocketDelegate> theDelegate = delegate;
  6372.  
  6373.                         if (delegateQueue && [theDelegate respondsToSelector:@selector(socket:didWritePartialDataOfLength:tag:)])
  6374.                         {
  6375.                                 long theWriteTag = currentWrite->tag;
  6376.                                
  6377.                                 dispatch_async(delegateQueue, ^{ @autoreleasepool {
  6378.                                        
  6379.                                         [theDelegate socket:self didWritePartialDataOfLength:bytesWritten tag:theWriteTag];
  6380.                                 }});
  6381.                         }
  6382.                 }
  6383.         }
  6384.        
  6385.         // Check for errors
  6386.        
  6387.         if (error)
  6388.         {
  6389.                 [self closeWithError:[self errorWithErrno:errno reason:@"Error in write() function"]];
  6390.         }
  6391.        
  6392.         // Do not add any code here without first adding a return statement in the error case above.
  6393. }
  6394.  
  6395. - (void)completeCurrentWrite
  6396. {
  6397.         LogTrace();
  6398.        
  6399.         NSAssert(currentWrite, @"Trying to complete current write when there is no current write.");
  6400.        
  6401.  
  6402.         __strong id<GCDAsyncSocketDelegate> theDelegate = delegate;
  6403.        
  6404.         if (delegateQueue && [theDelegate respondsToSelector:@selector(socket:didWriteDataWithTag:)])
  6405.         {
  6406.                 long theWriteTag = currentWrite->tag;
  6407.                
  6408.                 dispatch_async(delegateQueue, ^{ @autoreleasepool {
  6409.                        
  6410.                         [theDelegate socket:self didWriteDataWithTag:theWriteTag];
  6411.                 }});
  6412.         }
  6413.        
  6414.         [self endCurrentWrite];
  6415. }
  6416.  
  6417. - (void)endCurrentWrite
  6418. {
  6419.         if (writeTimer)
  6420.         {
  6421.                 dispatch_source_cancel(writeTimer);
  6422.                 writeTimer = NULL;
  6423.         }
  6424.        
  6425.         currentWrite = nil;
  6426. }
  6427.  
  6428. - (void)setupWriteTimerWithTimeout:(NSTimeInterval)timeout
  6429. {
  6430.         if (timeout >= 0.0)
  6431.         {
  6432.                 writeTimer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, socketQueue);
  6433.                
  6434.                 __weak GCDAsyncSocket *weakSelf = self;
  6435.                
  6436.                 dispatch_source_set_event_handler(writeTimer, ^{ @autoreleasepool {
  6437.                 #pragma clang diagnostic push
  6438.                 #pragma clang diagnostic warning "-Wimplicit-retain-self"
  6439.                        
  6440.                         __strong GCDAsyncSocket *strongSelf = weakSelf;
  6441.                         if (strongSelf == nil) return_from_block;
  6442.                        
  6443.                         [strongSelf doWriteTimeout];
  6444.                        
  6445.                 #pragma clang diagnostic pop
  6446.                 }});
  6447.                
  6448.                 #if !OS_OBJECT_USE_OBJC
  6449.                 dispatch_source_t theWriteTimer = writeTimer;
  6450.                 dispatch_source_set_cancel_handler(writeTimer, ^{
  6451.                 #pragma clang diagnostic push
  6452.                 #pragma clang diagnostic warning "-Wimplicit-retain-self"
  6453.                        
  6454.                         LogVerbose(@"dispatch_release(writeTimer)");
  6455.                         dispatch_release(theWriteTimer);
  6456.                        
  6457.                 #pragma clang diagnostic pop
  6458.                 });
  6459.                 #endif
  6460.                
  6461.                 dispatch_time_t tt = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(timeout * NSEC_PER_SEC));
  6462.                
  6463.                 dispatch_source_set_timer(writeTimer, tt, DISPATCH_TIME_FOREVER, 0);
  6464.                 dispatch_resume(writeTimer);
  6465.         }
  6466. }
  6467.  
  6468. - (void)doWriteTimeout
  6469. {
  6470.         // This is a little bit tricky.
  6471.         // Ideally we'd like to synchronously query the delegate about a timeout extension.
  6472.         // But if we do so synchronously we risk a possible deadlock.
  6473.         // So instead we have to do so asynchronously, and callback to ourselves from within the delegate block.
  6474.        
  6475.         flags |= kWritesPaused;
  6476.        
  6477.         __strong id<GCDAsyncSocketDelegate> theDelegate = delegate;
  6478.  
  6479.         if (delegateQueue && [theDelegate respondsToSelector:@selector(socket:shouldTimeoutWriteWithTag:elapsed:bytesDone:)])
  6480.         {
  6481.                 GCDAsyncWritePacket *theWrite = currentWrite;
  6482.                
  6483.                 dispatch_async(delegateQueue, ^{ @autoreleasepool {
  6484.                        
  6485.                         NSTimeInterval timeoutExtension = 0.0;
  6486.                        
  6487.                         timeoutExtension = [theDelegate socket:self shouldTimeoutWriteWithTag:theWrite->tag
  6488.                                                                                       elapsed:theWrite->timeout
  6489.                                                                                     bytesDone:theWrite->bytesDone];
  6490.                        
  6491.             dispatch_async(self->socketQueue, ^{ @autoreleasepool {
  6492.                                
  6493.                                 [self doWriteTimeoutWithExtension:timeoutExtension];
  6494.                         }});
  6495.                 }});
  6496.         }
  6497.         else
  6498.         {
  6499.                 [self doWriteTimeoutWithExtension:0.0];
  6500.         }
  6501. }
  6502.  
  6503. - (void)doWriteTimeoutWithExtension:(NSTimeInterval)timeoutExtension
  6504. {
  6505.         if (currentWrite)
  6506.         {
  6507.                 if (timeoutExtension > 0.0)
  6508.                 {
  6509.                         currentWrite->timeout += timeoutExtension;
  6510.                        
  6511.                         // Reschedule the timer
  6512.                         dispatch_time_t tt = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(timeoutExtension * NSEC_PER_SEC));
  6513.                         dispatch_source_set_timer(writeTimer, tt, DISPATCH_TIME_FOREVER, 0);
  6514.                        
  6515.                         // Unpause writes, and continue
  6516.                         flags &= ~kWritesPaused;
  6517.                         [self doWriteData];
  6518.                 }
  6519.                 else
  6520.                 {
  6521.                         LogVerbose(@"WriteTimeout");
  6522.                        
  6523.                         [self closeWithError:[self writeTimeoutError]];
  6524.                 }
  6525.         }
  6526. }
  6527.  
  6528. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  6529. #pragma mark Security
  6530. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  6531.  
  6532. - (void)startTLS:(NSDictionary *)tlsSettings
  6533. {
  6534.         LogTrace();
  6535.        
  6536.         if (tlsSettings == nil)
  6537.     {
  6538.         // Passing nil/NULL to CFReadStreamSetProperty will appear to work the same as passing an empty dictionary,
  6539.         // but causes problems if we later try to fetch the remote host's certificate.
  6540.         //
  6541.         // To be exact, it causes the following to return NULL instead of the normal result:
  6542.         // CFReadStreamCopyProperty(readStream, kCFStreamPropertySSLPeerCertificates)
  6543.         //
  6544.         // So we use an empty dictionary instead, which works perfectly.
  6545.        
  6546.         tlsSettings = [NSDictionary dictionary];
  6547.     }
  6548.        
  6549.         GCDAsyncSpecialPacket *packet = [[GCDAsyncSpecialPacket alloc] initWithTLSSettings:tlsSettings];
  6550.        
  6551.         dispatch_async(socketQueue, ^{ @autoreleasepool {
  6552.                
  6553.         if ((self->flags & kSocketStarted) && !(self->flags & kQueuedTLS) && !(self->flags & kForbidReadsWrites))
  6554.                 {
  6555.             [self->readQueue addObject:packet];
  6556.             [self->writeQueue addObject:packet];
  6557.                        
  6558.             self->flags |= kQueuedTLS;
  6559.                        
  6560.                         [self maybeDequeueRead];
  6561.                         [self maybeDequeueWrite];
  6562.                 }
  6563.         }});
  6564.        
  6565. }
  6566.  
  6567. - (void)maybeStartTLS
  6568. {
  6569.         // We can't start TLS until:
  6570.         // - All queued reads prior to the user calling startTLS are complete
  6571.         // - All queued writes prior to the user calling startTLS are complete
  6572.         //
  6573.         // We'll know these conditions are met when both kStartingReadTLS and kStartingWriteTLS are set
  6574.        
  6575.         if ((flags & kStartingReadTLS) && (flags & kStartingWriteTLS))
  6576.         {
  6577.                 BOOL useSecureTransport = YES;
  6578.                
  6579.                 #if TARGET_OS_IPHONE
  6580.                 {
  6581.                         GCDAsyncSpecialPacket *tlsPacket = (GCDAsyncSpecialPacket *)currentRead;
  6582.             NSDictionary *tlsSettings = @{};
  6583.             if (tlsPacket) {
  6584.                 tlsSettings = tlsPacket->tlsSettings;
  6585.             }
  6586.                         NSNumber *value = [tlsSettings objectForKey:GCDAsyncSocketUseCFStreamForTLS];
  6587.                         if (value && [value boolValue])
  6588.                                 useSecureTransport = NO;
  6589.                 }
  6590.                 #endif
  6591.                
  6592.                 if (useSecureTransport)
  6593.                 {
  6594.                         [self ssl_startTLS];
  6595.                 }
  6596.                 else
  6597.                 {
  6598.                 #if TARGET_OS_IPHONE
  6599.                         [self cf_startTLS];
  6600.                 #endif
  6601.                 }
  6602.         }
  6603. }
  6604.  
  6605. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  6606. #pragma mark Security via SecureTransport
  6607. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  6608.  
  6609. - (OSStatus)sslReadWithBuffer:(void *)buffer length:(size_t *)bufferLength
  6610. {
  6611.         LogVerbose(@"sslReadWithBuffer:%p length:%lu", buffer, (unsigned long)*bufferLength);
  6612.        
  6613.         if ((socketFDBytesAvailable == 0) && ([sslPreBuffer availableBytes] == 0))
  6614.         {
  6615.                 LogVerbose(@"%@ - No data available to read...", THIS_METHOD);
  6616.                
  6617.                 // No data available to read.
  6618.                 //
  6619.                 // Need to wait for readSource to fire and notify us of
  6620.                 // available data in the socket's internal read buffer.
  6621.                
  6622.                 [self resumeReadSource];
  6623.                
  6624.                 *bufferLength = 0;
  6625.                 return errSSLWouldBlock;
  6626.         }
  6627.        
  6628.         size_t totalBytesRead = 0;
  6629.         size_t totalBytesLeftToBeRead = *bufferLength;
  6630.        
  6631.         BOOL done = NO;
  6632.         BOOL socketError = NO;
  6633.        
  6634.         //
  6635.         // STEP 1 : READ FROM SSL PRE BUFFER
  6636.         //
  6637.        
  6638.         size_t sslPreBufferLength = [sslPreBuffer availableBytes];
  6639.        
  6640.         if (sslPreBufferLength > 0)
  6641.         {
  6642.                 LogVerbose(@"%@: Reading from SSL pre buffer...", THIS_METHOD);
  6643.                
  6644.                 size_t bytesToCopy;
  6645.                 if (sslPreBufferLength > totalBytesLeftToBeRead)
  6646.                         bytesToCopy = totalBytesLeftToBeRead;
  6647.                 else
  6648.                         bytesToCopy = sslPreBufferLength;
  6649.                
  6650.                 LogVerbose(@"%@: Copying %zu bytes from sslPreBuffer", THIS_METHOD, bytesToCopy);
  6651.                
  6652.                 memcpy(buffer, [sslPreBuffer readBuffer], bytesToCopy);
  6653.                 [sslPreBuffer didRead:bytesToCopy];
  6654.                
  6655.                 LogVerbose(@"%@: sslPreBuffer.length = %zu", THIS_METHOD, [sslPreBuffer availableBytes]);
  6656.                
  6657.                 totalBytesRead += bytesToCopy;
  6658.                 totalBytesLeftToBeRead -= bytesToCopy;
  6659.                
  6660.                 done = (totalBytesLeftToBeRead == 0);
  6661.                
  6662.                 if (done) LogVerbose(@"%@: Complete", THIS_METHOD);
  6663.         }
  6664.        
  6665.         //
  6666.         // STEP 2 : READ FROM SOCKET
  6667.         //
  6668.        
  6669.         if (!done && (socketFDBytesAvailable > 0))
  6670.         {
  6671.                 LogVerbose(@"%@: Reading from socket...", THIS_METHOD);
  6672.                
  6673.                 int socketFD = (socket4FD != SOCKET_NULL) ? socket4FD : (socket6FD != SOCKET_NULL) ? socket6FD : socketUN;
  6674.                
  6675.                 BOOL readIntoPreBuffer;
  6676.                 size_t bytesToRead;
  6677.                 uint8_t *buf;
  6678.                
  6679.                 if (socketFDBytesAvailable > totalBytesLeftToBeRead)
  6680.                 {
  6681.                         // Read all available data from socket into sslPreBuffer.
  6682.                         // Then copy requested amount into dataBuffer.
  6683.                        
  6684.                         LogVerbose(@"%@: Reading into sslPreBuffer...", THIS_METHOD);
  6685.                        
  6686.                         [sslPreBuffer ensureCapacityForWrite:socketFDBytesAvailable];
  6687.                        
  6688.                         readIntoPreBuffer = YES;
  6689.                         bytesToRead = (size_t)socketFDBytesAvailable;
  6690.                         buf = [sslPreBuffer writeBuffer];
  6691.                 }
  6692.                 else
  6693.                 {
  6694.                         // Read available data from socket directly into dataBuffer.
  6695.                        
  6696.                         LogVerbose(@"%@: Reading directly into dataBuffer...", THIS_METHOD);
  6697.                        
  6698.                         readIntoPreBuffer = NO;
  6699.                         bytesToRead = totalBytesLeftToBeRead;
  6700.                         buf = (uint8_t *)buffer + totalBytesRead;
  6701.                 }
  6702.                
  6703.                 ssize_t result = read(socketFD, buf, bytesToRead);
  6704.                 LogVerbose(@"%@: read from socket = %zd", THIS_METHOD, result);
  6705.                
  6706.                 if (result < 0)
  6707.                 {
  6708.                         LogVerbose(@"%@: read errno = %i", THIS_METHOD, errno);
  6709.                        
  6710.                         if (errno != EWOULDBLOCK)
  6711.                         {
  6712.                                 socketError = YES;
  6713.                         }
  6714.                        
  6715.                         socketFDBytesAvailable = 0;
  6716.                 }
  6717.                 else if (result == 0)
  6718.                 {
  6719.                         LogVerbose(@"%@: read EOF", THIS_METHOD);
  6720.                        
  6721.                         socketError = YES;
  6722.                         socketFDBytesAvailable = 0;
  6723.                 }
  6724.                 else
  6725.                 {
  6726.                         size_t bytesReadFromSocket = result;
  6727.                        
  6728.                         if (socketFDBytesAvailable > bytesReadFromSocket)
  6729.                                 socketFDBytesAvailable -= bytesReadFromSocket;
  6730.                         else
  6731.                                 socketFDBytesAvailable = 0;
  6732.                        
  6733.                         if (readIntoPreBuffer)
  6734.                         {
  6735.                                 [sslPreBuffer didWrite:bytesReadFromSocket];
  6736.                                
  6737.                                 size_t bytesToCopy = MIN(totalBytesLeftToBeRead, bytesReadFromSocket);
  6738.                                
  6739.                                 LogVerbose(@"%@: Copying %zu bytes out of sslPreBuffer", THIS_METHOD, bytesToCopy);
  6740.                                
  6741.                                 memcpy((uint8_t *)buffer + totalBytesRead, [sslPreBuffer readBuffer], bytesToCopy);
  6742.                                 [sslPreBuffer didRead:bytesToCopy];
  6743.                                
  6744.                                 totalBytesRead += bytesToCopy;
  6745.                                 totalBytesLeftToBeRead -= bytesToCopy;
  6746.                                
  6747.                                 LogVerbose(@"%@: sslPreBuffer.length = %zu", THIS_METHOD, [sslPreBuffer availableBytes]);
  6748.                         }
  6749.                         else
  6750.                         {
  6751.                                 totalBytesRead += bytesReadFromSocket;
  6752.                                 totalBytesLeftToBeRead -= bytesReadFromSocket;
  6753.                         }
  6754.                        
  6755.                         done = (totalBytesLeftToBeRead == 0);
  6756.                        
  6757.                         if (done) LogVerbose(@"%@: Complete", THIS_METHOD);
  6758.                 }
  6759.         }
  6760.        
  6761.         *bufferLength = totalBytesRead;
  6762.        
  6763.         if (done)
  6764.                 return noErr;
  6765.        
  6766.         if (socketError)
  6767.                 return errSSLClosedAbort;
  6768.        
  6769.         return errSSLWouldBlock;
  6770. }
  6771.  
  6772. - (OSStatus)sslWriteWithBuffer:(const void *)buffer length:(size_t *)bufferLength
  6773. {
  6774.         if (!(flags & kSocketCanAcceptBytes))
  6775.         {
  6776.                 // Unable to write.
  6777.                 //
  6778.                 // Need to wait for writeSource to fire and notify us of
  6779.                 // available space in the socket's internal write buffer.
  6780.                
  6781.                 [self resumeWriteSource];
  6782.                
  6783.                 *bufferLength = 0;
  6784.                 return errSSLWouldBlock;
  6785.         }
  6786.        
  6787.         size_t bytesToWrite = *bufferLength;
  6788.         size_t bytesWritten = 0;
  6789.        
  6790.         BOOL done = NO;
  6791.         BOOL socketError = NO;
  6792.        
  6793.         int socketFD = (socket4FD != SOCKET_NULL) ? socket4FD : (socket6FD != SOCKET_NULL) ? socket6FD : socketUN;
  6794.        
  6795.         ssize_t result = write(socketFD, buffer, bytesToWrite);
  6796.        
  6797.         if (result < 0)
  6798.         {
  6799.                 if (errno != EWOULDBLOCK)
  6800.                 {
  6801.                         socketError = YES;
  6802.                 }
  6803.                
  6804.                 flags &= ~kSocketCanAcceptBytes;
  6805.         }
  6806.         else if (result == 0)
  6807.         {
  6808.                 flags &= ~kSocketCanAcceptBytes;
  6809.         }
  6810.         else
  6811.         {
  6812.                 bytesWritten = result;
  6813.                
  6814.                 done = (bytesWritten == bytesToWrite);
  6815.         }
  6816.        
  6817.         *bufferLength = bytesWritten;
  6818.        
  6819.         if (done)
  6820.                 return noErr;
  6821.        
  6822.         if (socketError)
  6823.                 return errSSLClosedAbort;
  6824.        
  6825.         return errSSLWouldBlock;
  6826. }
  6827.  
  6828. static OSStatus SSLReadFunction(SSLConnectionRef connection, void *data, size_t *dataLength)
  6829. {
  6830.         GCDAsyncSocket *asyncSocket = (__bridge GCDAsyncSocket *)connection;
  6831.        
  6832.         NSCAssert(dispatch_get_specific(asyncSocket->IsOnSocketQueueOrTargetQueueKey), @"What the deuce?");
  6833.        
  6834.         return [asyncSocket sslReadWithBuffer:data length:dataLength];
  6835. }
  6836.  
  6837. static OSStatus SSLWriteFunction(SSLConnectionRef connection, const void *data, size_t *dataLength)
  6838. {
  6839.         GCDAsyncSocket *asyncSocket = (__bridge GCDAsyncSocket *)connection;
  6840.        
  6841.         NSCAssert(dispatch_get_specific(asyncSocket->IsOnSocketQueueOrTargetQueueKey), @"What the deuce?");
  6842.        
  6843.         return [asyncSocket sslWriteWithBuffer:data length:dataLength];
  6844. }
  6845.  
  6846. - (void)ssl_startTLS
  6847. {
  6848.         LogTrace();
  6849.        
  6850.         LogVerbose(@"Starting TLS (via SecureTransport)...");
  6851.        
  6852.         OSStatus status;
  6853.        
  6854.         GCDAsyncSpecialPacket *tlsPacket = (GCDAsyncSpecialPacket *)currentRead;
  6855.         if (tlsPacket == nil) // Code to quiet the analyzer
  6856.         {
  6857.                 NSAssert(NO, @"Logic error");
  6858.                
  6859.                 [self closeWithError:[self otherError:@"Logic error"]];
  6860.                 return;
  6861.         }
  6862.         NSDictionary *tlsSettings = tlsPacket->tlsSettings;
  6863.        
  6864.         // Create SSLContext, and setup IO callbacks and connection ref
  6865.        
  6866.         NSNumber *isServerNumber = [tlsSettings objectForKey:(__bridge NSString *)kCFStreamSSLIsServer];
  6867.         BOOL isServer = [isServerNumber boolValue];
  6868.        
  6869.         #if TARGET_OS_IPHONE || (__MAC_OS_X_VERSION_MIN_REQUIRED >= 1080)
  6870.         {
  6871.                 if (isServer)
  6872.                         sslContext = SSLCreateContext(kCFAllocatorDefault, kSSLServerSide, kSSLStreamType);
  6873.                 else
  6874.                         sslContext = SSLCreateContext(kCFAllocatorDefault, kSSLClientSide, kSSLStreamType);
  6875.                
  6876.                 if (sslContext == NULL)
  6877.                 {
  6878.                         [self closeWithError:[self otherError:@"Error in SSLCreateContext"]];
  6879.                         return;
  6880.                 }
  6881.         }
  6882.         #else // (__MAC_OS_X_VERSION_MIN_REQUIRED < 1080)
  6883.         {
  6884.                 status = SSLNewContext(isServer, &sslContext);
  6885.                 if (status != noErr)
  6886.                 {
  6887.                         [self closeWithError:[self otherError:@"Error in SSLNewContext"]];
  6888.                         return;
  6889.                 }
  6890.         }
  6891.         #endif
  6892.        
  6893.         status = SSLSetIOFuncs(sslContext, &SSLReadFunction, &SSLWriteFunction);
  6894.         if (status != noErr)
  6895.         {
  6896.                 [self closeWithError:[self otherError:@"Error in SSLSetIOFuncs"]];
  6897.                 return;
  6898.         }
  6899.        
  6900.         status = SSLSetConnection(sslContext, (__bridge SSLConnectionRef)self);
  6901.         if (status != noErr)
  6902.         {
  6903.                 [self closeWithError:[self otherError:@"Error in SSLSetConnection"]];
  6904.                 return;
  6905.         }
  6906.  
  6907.  
  6908.         NSNumber *shouldManuallyEvaluateTrust = [tlsSettings objectForKey:GCDAsyncSocketManuallyEvaluateTrust];
  6909.         if ([shouldManuallyEvaluateTrust boolValue])
  6910.         {
  6911.                 if (isServer)
  6912.                 {
  6913.                         [self closeWithError:[self otherError:@"Manual trust validation is not supported for server sockets"]];
  6914.                         return;
  6915.                 }
  6916.                
  6917.                 status = SSLSetSessionOption(sslContext, kSSLSessionOptionBreakOnServerAuth, true);
  6918.                 if (status != noErr)
  6919.                 {
  6920.                         [self closeWithError:[self otherError:@"Error in SSLSetSessionOption"]];
  6921.                         return;
  6922.                 }
  6923.                
  6924.                 #if !TARGET_OS_IPHONE && (__MAC_OS_X_VERSION_MIN_REQUIRED < 1080)
  6925.                
  6926.                 // Note from Apple's documentation:
  6927.                 //
  6928.                 // It is only necessary to call SSLSetEnableCertVerify on the Mac prior to OS X 10.8.
  6929.                 // On OS X 10.8 and later setting kSSLSessionOptionBreakOnServerAuth always disables the
  6930.                 // built-in trust evaluation. All versions of iOS behave like OS X 10.8 and thus
  6931.                 // SSLSetEnableCertVerify is not available on that platform at all.
  6932.                
  6933.                 status = SSLSetEnableCertVerify(sslContext, NO);
  6934.                 if (status != noErr)
  6935.                 {
  6936.                         [self closeWithError:[self otherError:@"Error in SSLSetEnableCertVerify"]];
  6937.                         return;
  6938.                 }
  6939.                
  6940.                 #endif
  6941.         }
  6942.  
  6943.         // Configure SSLContext from given settings
  6944.         //
  6945.         // Checklist:
  6946.         //  1. kCFStreamSSLPeerName
  6947.         //  2. kCFStreamSSLCertificates
  6948.         //  3. GCDAsyncSocketSSLPeerID
  6949.         //  4. GCDAsyncSocketSSLProtocolVersionMin
  6950.         //  5. GCDAsyncSocketSSLProtocolVersionMax
  6951.         //  6. GCDAsyncSocketSSLSessionOptionFalseStart
  6952.         //  7. GCDAsyncSocketSSLSessionOptionSendOneByteRecord
  6953.         //  8. GCDAsyncSocketSSLCipherSuites
  6954.         //  9. GCDAsyncSocketSSLDiffieHellmanParameters (Mac)
  6955.     // 10. GCDAsyncSocketSSLALPN
  6956.         //
  6957.         // Deprecated (throw error):
  6958.         // 10. kCFStreamSSLAllowsAnyRoot
  6959.         // 11. kCFStreamSSLAllowsExpiredRoots
  6960.         // 12. kCFStreamSSLAllowsExpiredCertificates
  6961.         // 13. kCFStreamSSLValidatesCertificateChain
  6962.         // 14. kCFStreamSSLLevel
  6963.        
  6964.         NSObject *value;
  6965.        
  6966.         // 1. kCFStreamSSLPeerName
  6967.        
  6968.         value = [tlsSettings objectForKey:(__bridge NSString *)kCFStreamSSLPeerName];
  6969.         if ([value isKindOfClass:[NSString class]])
  6970.         {
  6971.                 NSString *peerName = (NSString *)value;
  6972.                
  6973.                 const char *peer = [peerName UTF8String];
  6974.                 size_t peerLen = strlen(peer);
  6975.                
  6976.                 status = SSLSetPeerDomainName(sslContext, peer, peerLen);
  6977.                 if (status != noErr)
  6978.                 {
  6979.                         [self closeWithError:[self otherError:@"Error in SSLSetPeerDomainName"]];
  6980.                         return;
  6981.                 }
  6982.         }
  6983.         else if (value)
  6984.         {
  6985.                 NSAssert(NO, @"Invalid value for kCFStreamSSLPeerName. Value must be of type NSString.");
  6986.                
  6987.                 [self closeWithError:[self otherError:@"Invalid value for kCFStreamSSLPeerName."]];
  6988.                 return;
  6989.         }
  6990.        
  6991.         // 2. kCFStreamSSLCertificates
  6992.        
  6993.         value = [tlsSettings objectForKey:(__bridge NSString *)kCFStreamSSLCertificates];
  6994.         if ([value isKindOfClass:[NSArray class]])
  6995.         {
  6996.                 NSArray *certs = (NSArray *)value;
  6997.                
  6998.                 status = SSLSetCertificate(sslContext, (__bridge CFArrayRef)certs);
  6999.                 if (status != noErr)
  7000.                 {
  7001.                         [self closeWithError:[self otherError:@"Error in SSLSetCertificate"]];
  7002.                         return;
  7003.                 }
  7004.         }
  7005.         else if (value)
  7006.         {
  7007.                 NSAssert(NO, @"Invalid value for kCFStreamSSLCertificates. Value must be of type NSArray.");
  7008.                
  7009.                 [self closeWithError:[self otherError:@"Invalid value for kCFStreamSSLCertificates."]];
  7010.                 return;
  7011.         }
  7012.        
  7013.         // 3. GCDAsyncSocketSSLPeerID
  7014.        
  7015.         value = [tlsSettings objectForKey:GCDAsyncSocketSSLPeerID];
  7016.         if ([value isKindOfClass:[NSData class]])
  7017.         {
  7018.                 NSData *peerIdData = (NSData *)value;
  7019.                
  7020.                 status = SSLSetPeerID(sslContext, [peerIdData bytes], [peerIdData length]);
  7021.                 if (status != noErr)
  7022.                 {
  7023.                         [self closeWithError:[self otherError:@"Error in SSLSetPeerID"]];
  7024.                         return;
  7025.                 }
  7026.         }
  7027.         else if (value)
  7028.         {
  7029.                 NSAssert(NO, @"Invalid value for GCDAsyncSocketSSLPeerID. Value must be of type NSData."
  7030.                              @" (You can convert strings to data using a method like"
  7031.                              @" [string dataUsingEncoding:NSUTF8StringEncoding])");
  7032.                
  7033.                 [self closeWithError:[self otherError:@"Invalid value for GCDAsyncSocketSSLPeerID."]];
  7034.                 return;
  7035.         }
  7036.        
  7037.         // 4. GCDAsyncSocketSSLProtocolVersionMin
  7038.        
  7039.         value = [tlsSettings objectForKey:GCDAsyncSocketSSLProtocolVersionMin];
  7040.         if ([value isKindOfClass:[NSNumber class]])
  7041.         {
  7042.                 SSLProtocol minProtocol = (SSLProtocol)[(NSNumber *)value intValue];
  7043.                 if (minProtocol != kSSLProtocolUnknown)
  7044.                 {
  7045.                         status = SSLSetProtocolVersionMin(sslContext, minProtocol);
  7046.                         if (status != noErr)
  7047.                         {
  7048.                                 [self closeWithError:[self otherError:@"Error in SSLSetProtocolVersionMin"]];
  7049.                                 return;
  7050.                         }
  7051.                 }
  7052.         }
  7053.         else if (value)
  7054.         {
  7055.                 NSAssert(NO, @"Invalid value for GCDAsyncSocketSSLProtocolVersionMin. Value must be of type NSNumber.");
  7056.                
  7057.                 [self closeWithError:[self otherError:@"Invalid value for GCDAsyncSocketSSLProtocolVersionMin."]];
  7058.                 return;
  7059.         }
  7060.        
  7061.         // 5. GCDAsyncSocketSSLProtocolVersionMax
  7062.        
  7063.         value = [tlsSettings objectForKey:GCDAsyncSocketSSLProtocolVersionMax];
  7064.         if ([value isKindOfClass:[NSNumber class]])
  7065.         {
  7066.                 SSLProtocol maxProtocol = (SSLProtocol)[(NSNumber *)value intValue];
  7067.                 if (maxProtocol != kSSLProtocolUnknown)
  7068.                 {
  7069.                         status = SSLSetProtocolVersionMax(sslContext, maxProtocol);
  7070.                         if (status != noErr)
  7071.                         {
  7072.                                 [self closeWithError:[self otherError:@"Error in SSLSetProtocolVersionMax"]];
  7073.                                 return;
  7074.                         }
  7075.                 }
  7076.         }
  7077.         else if (value)
  7078.         {
  7079.                 NSAssert(NO, @"Invalid value for GCDAsyncSocketSSLProtocolVersionMax. Value must be of type NSNumber.");
  7080.                
  7081.                 [self closeWithError:[self otherError:@"Invalid value for GCDAsyncSocketSSLProtocolVersionMax."]];
  7082.                 return;
  7083.         }
  7084.        
  7085.         // 6. GCDAsyncSocketSSLSessionOptionFalseStart
  7086.        
  7087.         value = [tlsSettings objectForKey:GCDAsyncSocketSSLSessionOptionFalseStart];
  7088.         if ([value isKindOfClass:[NSNumber class]])
  7089.         {
  7090.                 NSNumber *falseStart = (NSNumber *)value;
  7091.                 status = SSLSetSessionOption(sslContext, kSSLSessionOptionFalseStart, [falseStart boolValue]);
  7092.                 if (status != noErr)
  7093.                 {
  7094.                         [self closeWithError:[self otherError:@"Error in SSLSetSessionOption (kSSLSessionOptionFalseStart)"]];
  7095.                         return;
  7096.                 }
  7097.         }
  7098.         else if (value)
  7099.         {
  7100.                 NSAssert(NO, @"Invalid value for GCDAsyncSocketSSLSessionOptionFalseStart. Value must be of type NSNumber.");
  7101.                
  7102.                 [self closeWithError:[self otherError:@"Invalid value for GCDAsyncSocketSSLSessionOptionFalseStart."]];
  7103.                 return;
  7104.         }
  7105.        
  7106.         // 7. GCDAsyncSocketSSLSessionOptionSendOneByteRecord
  7107.        
  7108.         value = [tlsSettings objectForKey:GCDAsyncSocketSSLSessionOptionSendOneByteRecord];
  7109.         if ([value isKindOfClass:[NSNumber class]])
  7110.         {
  7111.                 NSNumber *oneByteRecord = (NSNumber *)value;
  7112.                 status = SSLSetSessionOption(sslContext, kSSLSessionOptionSendOneByteRecord, [oneByteRecord boolValue]);
  7113.                 if (status != noErr)
  7114.                 {
  7115.                         [self closeWithError:
  7116.                           [self otherError:@"Error in SSLSetSessionOption (kSSLSessionOptionSendOneByteRecord)"]];
  7117.                         return;
  7118.                 }
  7119.         }
  7120.         else if (value)
  7121.         {
  7122.                 NSAssert(NO, @"Invalid value for GCDAsyncSocketSSLSessionOptionSendOneByteRecord."
  7123.                              @" Value must be of type NSNumber.");
  7124.                
  7125.                 [self closeWithError:[self otherError:@"Invalid value for GCDAsyncSocketSSLSessionOptionSendOneByteRecord."]];
  7126.                 return;
  7127.         }
  7128.        
  7129.         // 8. GCDAsyncSocketSSLCipherSuites
  7130.        
  7131.         value = [tlsSettings objectForKey:GCDAsyncSocketSSLCipherSuites];
  7132.         if ([value isKindOfClass:[NSArray class]])
  7133.         {
  7134.                 NSArray *cipherSuites = (NSArray *)value;
  7135.                 NSUInteger numberCiphers = [cipherSuites count];
  7136.                 SSLCipherSuite ciphers[numberCiphers];
  7137.                
  7138.                 NSUInteger cipherIndex;
  7139.                 for (cipherIndex = 0; cipherIndex < numberCiphers; cipherIndex++)
  7140.                 {
  7141.                         NSNumber *cipherObject = [cipherSuites objectAtIndex:cipherIndex];
  7142.                         ciphers[cipherIndex] = (SSLCipherSuite)[cipherObject unsignedIntValue];
  7143.                 }
  7144.                
  7145.                 status = SSLSetEnabledCiphers(sslContext, ciphers, numberCiphers);
  7146.                 if (status != noErr)
  7147.                 {
  7148.                         [self closeWithError:[self otherError:@"Error in SSLSetEnabledCiphers"]];
  7149.                         return;
  7150.                 }
  7151.         }
  7152.         else if (value)
  7153.         {
  7154.                 NSAssert(NO, @"Invalid value for GCDAsyncSocketSSLCipherSuites. Value must be of type NSArray.");
  7155.                
  7156.                 [self closeWithError:[self otherError:@"Invalid value for GCDAsyncSocketSSLCipherSuites."]];
  7157.                 return;
  7158.         }
  7159.        
  7160.         // 9. GCDAsyncSocketSSLDiffieHellmanParameters
  7161.        
  7162.         #if !TARGET_OS_IPHONE
  7163.         value = [tlsSettings objectForKey:GCDAsyncSocketSSLDiffieHellmanParameters];
  7164.         if ([value isKindOfClass:[NSData class]])
  7165.         {
  7166.                 NSData *diffieHellmanData = (NSData *)value;
  7167.                
  7168.                 status = SSLSetDiffieHellmanParams(sslContext, [diffieHellmanData bytes], [diffieHellmanData length]);
  7169.                 if (status != noErr)
  7170.                 {
  7171.                         [self closeWithError:[self otherError:@"Error in SSLSetDiffieHellmanParams"]];
  7172.                         return;
  7173.                 }
  7174.         }
  7175.         else if (value)
  7176.         {
  7177.                 NSAssert(NO, @"Invalid value for GCDAsyncSocketSSLDiffieHellmanParameters. Value must be of type NSData.");
  7178.                
  7179.                 [self closeWithError:[self otherError:@"Invalid value for GCDAsyncSocketSSLDiffieHellmanParameters."]];
  7180.                 return;
  7181.         }
  7182.         #endif
  7183.  
  7184.     // 10. kCFStreamSSLCertificates
  7185.     value = [tlsSettings objectForKey:GCDAsyncSocketSSLALPN];
  7186.     if ([value isKindOfClass:[NSArray class]])
  7187.     {
  7188.         if (@available(iOS 11.0, macOS 10.13, tvOS 11.0, *))
  7189.         {
  7190.             CFArrayRef protocols = (__bridge CFArrayRef)((NSArray *) value);
  7191.             status = SSLSetALPNProtocols(sslContext, protocols);
  7192.             if (status != noErr)
  7193.             {
  7194.                 [self closeWithError:[self otherError:@"Error in SSLSetALPNProtocols"]];
  7195.                 return;
  7196.             }
  7197.         }
  7198.         else
  7199.         {
  7200.             NSAssert(NO, @"Security option unavailable - GCDAsyncSocketSSLALPN"
  7201.                      @" - iOS 11.0, macOS 10.13 required");
  7202.             [self closeWithError:[self otherError:@"Security option unavailable - GCDAsyncSocketSSLALPN"]];
  7203.         }
  7204.     }
  7205.     else if (value)
  7206.     {
  7207.         NSAssert(NO, @"Invalid value for GCDAsyncSocketSSLALPN. Value must be of type NSArray.");
  7208.        
  7209.         [self closeWithError:[self otherError:@"Invalid value for GCDAsyncSocketSSLALPN."]];
  7210.         return;
  7211.     }
  7212.    
  7213.         // DEPRECATED checks
  7214.        
  7215.         // 10. kCFStreamSSLAllowsAnyRoot
  7216.        
  7217.         #pragma clang diagnostic push
  7218.         #pragma clang diagnostic ignored "-Wdeprecated-declarations"
  7219.         value = [tlsSettings objectForKey:(__bridge NSString *)kCFStreamSSLAllowsAnyRoot];
  7220.         #pragma clang diagnostic pop
  7221.         if (value)
  7222.         {
  7223.                 NSAssert(NO, @"Security option unavailable - kCFStreamSSLAllowsAnyRoot"
  7224.                              @" - You must use manual trust evaluation");
  7225.                
  7226.                 [self closeWithError:[self otherError:@"Security option unavailable - kCFStreamSSLAllowsAnyRoot"]];
  7227.                 return;
  7228.         }
  7229.        
  7230.         // 11. kCFStreamSSLAllowsExpiredRoots
  7231.        
  7232.         #pragma clang diagnostic push
  7233.         #pragma clang diagnostic ignored "-Wdeprecated-declarations"
  7234.         value = [tlsSettings objectForKey:(__bridge NSString *)kCFStreamSSLAllowsExpiredRoots];
  7235.         #pragma clang diagnostic pop
  7236.         if (value)
  7237.         {
  7238.                 NSAssert(NO, @"Security option unavailable - kCFStreamSSLAllowsExpiredRoots"
  7239.                              @" - You must use manual trust evaluation");
  7240.                
  7241.                 [self closeWithError:[self otherError:@"Security option unavailable - kCFStreamSSLAllowsExpiredRoots"]];
  7242.                 return;
  7243.         }
  7244.        
  7245.         // 12. kCFStreamSSLValidatesCertificateChain
  7246.        
  7247.         #pragma clang diagnostic push
  7248.         #pragma clang diagnostic ignored "-Wdeprecated-declarations"
  7249.         value = [tlsSettings objectForKey:(__bridge NSString *)kCFStreamSSLValidatesCertificateChain];
  7250.         #pragma clang diagnostic pop
  7251.         if (value)
  7252.         {
  7253.                 NSAssert(NO, @"Security option unavailable - kCFStreamSSLValidatesCertificateChain"
  7254.                              @" - You must use manual trust evaluation");
  7255.                
  7256.                 [self closeWithError:[self otherError:@"Security option unavailable - kCFStreamSSLValidatesCertificateChain"]];
  7257.                 return;
  7258.         }
  7259.        
  7260.         // 13. kCFStreamSSLAllowsExpiredCertificates
  7261.        
  7262.         #pragma clang diagnostic push
  7263.         #pragma clang diagnostic ignored "-Wdeprecated-declarations"
  7264.         value = [tlsSettings objectForKey:(__bridge NSString *)kCFStreamSSLAllowsExpiredCertificates];
  7265.         #pragma clang diagnostic pop
  7266.         if (value)
  7267.         {
  7268.                 NSAssert(NO, @"Security option unavailable - kCFStreamSSLAllowsExpiredCertificates"
  7269.                              @" - You must use manual trust evaluation");
  7270.                
  7271.                 [self closeWithError:[self otherError:@"Security option unavailable - kCFStreamSSLAllowsExpiredCertificates"]];
  7272.                 return;
  7273.         }
  7274.        
  7275.         // 14. kCFStreamSSLLevel
  7276.        
  7277.         #pragma clang diagnostic push
  7278.         #pragma clang diagnostic ignored "-Wdeprecated-declarations"
  7279.         value = [tlsSettings objectForKey:(__bridge NSString *)kCFStreamSSLLevel];
  7280.         #pragma clang diagnostic pop
  7281.         if (value)
  7282.         {
  7283.                 NSAssert(NO, @"Security option unavailable - kCFStreamSSLLevel"
  7284.                              @" - You must use GCDAsyncSocketSSLProtocolVersionMin & GCDAsyncSocketSSLProtocolVersionMax");
  7285.                
  7286.                 [self closeWithError:[self otherError:@"Security option unavailable - kCFStreamSSLLevel"]];
  7287.                 return;
  7288.         }
  7289.        
  7290.         // Setup the sslPreBuffer
  7291.         //
  7292.         // Any data in the preBuffer needs to be moved into the sslPreBuffer,
  7293.         // as this data is now part of the secure read stream.
  7294.        
  7295.         sslPreBuffer = [[GCDAsyncSocketPreBuffer alloc] initWithCapacity:(1024 * 4)];
  7296.        
  7297.         size_t preBufferLength  = [preBuffer availableBytes];
  7298.        
  7299.         if (preBufferLength > 0)
  7300.         {
  7301.                 [sslPreBuffer ensureCapacityForWrite:preBufferLength];
  7302.                
  7303.                 memcpy([sslPreBuffer writeBuffer], [preBuffer readBuffer], preBufferLength);
  7304.                 [preBuffer didRead:preBufferLength];
  7305.                 [sslPreBuffer didWrite:preBufferLength];
  7306.         }
  7307.        
  7308.         sslErrCode = lastSSLHandshakeError = noErr;
  7309.        
  7310.         // Start the SSL Handshake process
  7311.        
  7312.         [self ssl_continueSSLHandshake];
  7313. }
  7314.  
  7315. - (void)ssl_continueSSLHandshake
  7316. {
  7317.         LogTrace();
  7318.        
  7319.         // If the return value is noErr, the session is ready for normal secure communication.
  7320.         // If the return value is errSSLWouldBlock, the SSLHandshake function must be called again.
  7321.         // If the return value is errSSLServerAuthCompleted, we ask delegate if we should trust the
  7322.         // server and then call SSLHandshake again to resume the handshake or close the connection
  7323.         // errSSLPeerBadCert SSL error.
  7324.         // Otherwise, the return value indicates an error code.
  7325.        
  7326.         OSStatus status = SSLHandshake(sslContext);
  7327.         lastSSLHandshakeError = status;
  7328.        
  7329.         if (status == noErr)
  7330.         {
  7331.                 LogVerbose(@"SSLHandshake complete");
  7332.                
  7333.                 flags &= ~kStartingReadTLS;
  7334.                 flags &= ~kStartingWriteTLS;
  7335.                
  7336.                 flags |=  kSocketSecure;
  7337.                
  7338.                 __strong id<GCDAsyncSocketDelegate> theDelegate = delegate;
  7339.  
  7340.                 if (delegateQueue && [theDelegate respondsToSelector:@selector(socketDidSecure:)])
  7341.                 {
  7342.                         dispatch_async(delegateQueue, ^{ @autoreleasepool {
  7343.                                
  7344.                                 [theDelegate socketDidSecure:self];
  7345.                         }});
  7346.                 }
  7347.                
  7348.                 [self endCurrentRead];
  7349.                 [self endCurrentWrite];
  7350.                
  7351.                 [self maybeDequeueRead];
  7352.                 [self maybeDequeueWrite];
  7353.         }
  7354.         else if (status == errSSLPeerAuthCompleted)
  7355.         {
  7356.                 LogVerbose(@"SSLHandshake peerAuthCompleted - awaiting delegate approval");
  7357.                
  7358.                 __block SecTrustRef trust = NULL;
  7359.                 status = SSLCopyPeerTrust(sslContext, &trust);
  7360.                 if (status != noErr)
  7361.                 {
  7362.                         [self closeWithError:[self sslError:status]];
  7363.                         return;
  7364.                 }
  7365.                
  7366.                 int aStateIndex = stateIndex;
  7367.                 dispatch_queue_t theSocketQueue = socketQueue;
  7368.                
  7369.                 __weak GCDAsyncSocket *weakSelf = self;
  7370.                
  7371.                 void (^comletionHandler)(BOOL) = ^(BOOL shouldTrust){ @autoreleasepool {
  7372.                 #pragma clang diagnostic push
  7373.                 #pragma clang diagnostic warning "-Wimplicit-retain-self"
  7374.                        
  7375.                         dispatch_async(theSocketQueue, ^{ @autoreleasepool {
  7376.                                
  7377.                                 if (trust) {
  7378.                                         CFRelease(trust);
  7379.                                         trust = NULL;
  7380.                                 }
  7381.                                
  7382.                                 __strong GCDAsyncSocket *strongSelf = weakSelf;
  7383.                                 if (strongSelf)
  7384.                                 {
  7385.                                         [strongSelf ssl_shouldTrustPeer:shouldTrust stateIndex:aStateIndex];
  7386.                                 }
  7387.                         }});
  7388.                        
  7389.                 #pragma clang diagnostic pop
  7390.                 }};
  7391.                
  7392.                 __strong id<GCDAsyncSocketDelegate> theDelegate = delegate;
  7393.                
  7394.                 if (delegateQueue && [theDelegate respondsToSelector:@selector(socket:didReceiveTrust:completionHandler:)])
  7395.                 {
  7396.                         dispatch_async(delegateQueue, ^{ @autoreleasepool {
  7397.                        
  7398.                                 [theDelegate socket:self didReceiveTrust:trust completionHandler:comletionHandler];
  7399.                         }});
  7400.                 }
  7401.                 else
  7402.                 {
  7403.                         if (trust) {
  7404.                                 CFRelease(trust);
  7405.                                 trust = NULL;
  7406.                         }
  7407.                        
  7408.                         NSString *msg = @"GCDAsyncSocketManuallyEvaluateTrust specified in tlsSettings,"
  7409.                                         @" but delegate doesn't implement socket:shouldTrustPeer:";
  7410.                        
  7411.                         [self closeWithError:[self otherError:msg]];
  7412.                         return;
  7413.                 }
  7414.         }
  7415.         else if (status == errSSLWouldBlock)
  7416.         {
  7417.                 LogVerbose(@"SSLHandshake continues...");
  7418.                
  7419.                 // Handshake continues...
  7420.                 //
  7421.                 // This method will be called again from doReadData or doWriteData.
  7422.         }
  7423.         else
  7424.         {
  7425.                 [self closeWithError:[self sslError:status]];
  7426.         }
  7427. }
  7428.  
  7429. - (void)ssl_shouldTrustPeer:(BOOL)shouldTrust stateIndex:(int)aStateIndex
  7430. {
  7431.         LogTrace();
  7432.        
  7433.         if (aStateIndex != stateIndex)
  7434.         {
  7435.                 LogInfo(@"Ignoring ssl_shouldTrustPeer - invalid state (maybe disconnected)");
  7436.                
  7437.                 // One of the following is true
  7438.                 // - the socket was disconnected
  7439.                 // - the startTLS operation timed out
  7440.                 // - the completionHandler was already invoked once
  7441.                
  7442.                 return;
  7443.         }
  7444.        
  7445.         // Increment stateIndex to ensure completionHandler can only be called once.
  7446.         stateIndex++;
  7447.        
  7448.         if (shouldTrust)
  7449.         {
  7450.         NSAssert(lastSSLHandshakeError == errSSLPeerAuthCompleted, @"ssl_shouldTrustPeer called when last error is %d and not errSSLPeerAuthCompleted", (int)lastSSLHandshakeError);
  7451.                 [self ssl_continueSSLHandshake];
  7452.         }
  7453.         else
  7454.         {
  7455.                 [self closeWithError:[self sslError:errSSLPeerBadCert]];
  7456.         }
  7457. }
  7458.  
  7459. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  7460. #pragma mark Security via CFStream
  7461. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  7462.  
  7463. #if TARGET_OS_IPHONE
  7464.  
  7465. - (void)cf_finishSSLHandshake
  7466. {
  7467.         LogTrace();
  7468.        
  7469.         if ((flags & kStartingReadTLS) && (flags & kStartingWriteTLS))
  7470.         {
  7471.                 flags &= ~kStartingReadTLS;
  7472.                 flags &= ~kStartingWriteTLS;
  7473.                
  7474.                 flags |= kSocketSecure;
  7475.                
  7476.                 __strong id<GCDAsyncSocketDelegate> theDelegate = delegate;
  7477.  
  7478.                 if (delegateQueue && [theDelegate respondsToSelector:@selector(socketDidSecure:)])
  7479.                 {
  7480.                         dispatch_async(delegateQueue, ^{ @autoreleasepool {
  7481.                                
  7482.                                 [theDelegate socketDidSecure:self];
  7483.                         }});
  7484.                 }
  7485.                
  7486.                 [self endCurrentRead];
  7487.                 [self endCurrentWrite];
  7488.                
  7489.                 [self maybeDequeueRead];
  7490.                 [self maybeDequeueWrite];
  7491.         }
  7492. }
  7493.  
  7494. - (void)cf_abortSSLHandshake:(NSError *)error
  7495. {
  7496.         LogTrace();
  7497.        
  7498.         if ((flags & kStartingReadTLS) && (flags & kStartingWriteTLS))
  7499.         {
  7500.                 flags &= ~kStartingReadTLS;
  7501.                 flags &= ~kStartingWriteTLS;
  7502.                
  7503.                 [self closeWithError:error];
  7504.         }
  7505. }
  7506.  
  7507. - (void)cf_startTLS
  7508. {
  7509.         LogTrace();
  7510.        
  7511.         LogVerbose(@"Starting TLS (via CFStream)...");
  7512.        
  7513.         if ([preBuffer availableBytes] > 0)
  7514.         {
  7515.                 NSString *msg = @"Invalid TLS transition. Handshake has already been read from socket.";
  7516.                
  7517.                 [self closeWithError:[self otherError:msg]];
  7518.                 return;
  7519.         }
  7520.        
  7521.         [self suspendReadSource];
  7522.         [self suspendWriteSource];
  7523.        
  7524.         socketFDBytesAvailable = 0;
  7525.         flags &= ~kSocketCanAcceptBytes;
  7526.         flags &= ~kSecureSocketHasBytesAvailable;
  7527.        
  7528.         flags |=  kUsingCFStreamForTLS;
  7529.        
  7530.         if (![self createReadAndWriteStream])
  7531.         {
  7532.                 [self closeWithError:[self otherError:@"Error in CFStreamCreatePairWithSocket"]];
  7533.                 return;
  7534.         }
  7535.        
  7536.         if (![self registerForStreamCallbacksIncludingReadWrite:YES])
  7537.         {
  7538.                 [self closeWithError:[self otherError:@"Error in CFStreamSetClient"]];
  7539.                 return;
  7540.         }
  7541.        
  7542.         if (![self addStreamsToRunLoop])
  7543.         {
  7544.                 [self closeWithError:[self otherError:@"Error in CFStreamScheduleWithRunLoop"]];
  7545.                 return;
  7546.         }
  7547.        
  7548.         NSAssert([currentRead isKindOfClass:[GCDAsyncSpecialPacket class]], @"Invalid read packet for startTLS");
  7549.         NSAssert([currentWrite isKindOfClass:[GCDAsyncSpecialPacket class]], @"Invalid write packet for startTLS");
  7550.        
  7551.         GCDAsyncSpecialPacket *tlsPacket = (GCDAsyncSpecialPacket *)currentRead;
  7552.         CFDictionaryRef tlsSettings = (__bridge CFDictionaryRef)tlsPacket->tlsSettings;
  7553.        
  7554.         // Getting an error concerning kCFStreamPropertySSLSettings ?
  7555.         // You need to add the CFNetwork framework to your iOS application.
  7556.        
  7557.         BOOL r1 = CFReadStreamSetProperty(readStream, kCFStreamPropertySSLSettings, tlsSettings);
  7558.         BOOL r2 = CFWriteStreamSetProperty(writeStream, kCFStreamPropertySSLSettings, tlsSettings);
  7559.        
  7560.         // For some reason, starting around the time of iOS 4.3,
  7561.         // the first call to set the kCFStreamPropertySSLSettings will return true,
  7562.         // but the second will return false.
  7563.         //
  7564.         // Order doesn't seem to matter.
  7565.         // So you could call CFReadStreamSetProperty and then CFWriteStreamSetProperty, or you could reverse the order.
  7566.         // Either way, the first call will return true, and the second returns false.
  7567.         //
  7568.         // Interestingly, this doesn't seem to affect anything.
  7569.         // Which is not altogether unusual, as the documentation seems to suggest that (for many settings)
  7570.         // setting it on one side of the stream automatically sets it for the other side of the stream.
  7571.         //
  7572.         // Although there isn't anything in the documentation to suggest that the second attempt would fail.
  7573.         //
  7574.         // Furthermore, this only seems to affect streams that are negotiating a security upgrade.
  7575.         // In other words, the socket gets connected, there is some back-and-forth communication over the unsecure
  7576.         // connection, and then a startTLS is issued.
  7577.         // So this mostly affects newer protocols (XMPP, IMAP) as opposed to older protocols (HTTPS).
  7578.        
  7579.         if (!r1 && !r2) // Yes, the && is correct - workaround for apple bug.
  7580.         {
  7581.                 [self closeWithError:[self otherError:@"Error in CFStreamSetProperty"]];
  7582.                 return;
  7583.         }
  7584.        
  7585.         if (![self openStreams])
  7586.         {
  7587.                 [self closeWithError:[self otherError:@"Error in CFStreamOpen"]];
  7588.                 return;
  7589.         }
  7590.        
  7591.         LogVerbose(@"Waiting for SSL Handshake to complete...");
  7592. }
  7593.  
  7594. #endif
  7595.  
  7596. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  7597. #pragma mark CFStream
  7598. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  7599.  
  7600. #if TARGET_OS_IPHONE
  7601.  
  7602. + (void)ignore:(id)_
  7603. {}
  7604.  
  7605. + (void)startCFStreamThreadIfNeeded
  7606. {
  7607.         LogTrace();
  7608.        
  7609.         static dispatch_once_t predicate;
  7610.         dispatch_once(&predicate, ^{
  7611.                
  7612.                 cfstreamThreadRetainCount = 0;
  7613.                 cfstreamThreadSetupQueue = dispatch_queue_create("GCDAsyncSocket-CFStreamThreadSetup", DISPATCH_QUEUE_SERIAL);
  7614.         });
  7615.        
  7616.         dispatch_sync(cfstreamThreadSetupQueue, ^{ @autoreleasepool {
  7617.                
  7618.                 if (++cfstreamThreadRetainCount == 1)
  7619.                 {
  7620.                         cfstreamThread = [[NSThread alloc] initWithTarget:self
  7621.                                                                  selector:@selector(cfstreamThread:)
  7622.                                                                    object:nil];
  7623.                         [cfstreamThread start];
  7624.                 }
  7625.         }});
  7626. }
  7627.  
  7628. + (void)stopCFStreamThreadIfNeeded
  7629. {
  7630.         LogTrace();
  7631.        
  7632.         // The creation of the cfstreamThread is relatively expensive.
  7633.         // So we'd like to keep it available for recycling.
  7634.         // However, there's a tradeoff here, because it shouldn't remain alive forever.
  7635.         // So what we're going to do is use a little delay before taking it down.
  7636.         // This way it can be reused properly in situations where multiple sockets are continually in flux.
  7637.        
  7638.         int delayInSeconds = 30;
  7639.         dispatch_time_t when = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
  7640.         dispatch_after(when, cfstreamThreadSetupQueue, ^{ @autoreleasepool {
  7641.         #pragma clang diagnostic push
  7642.         #pragma clang diagnostic warning "-Wimplicit-retain-self"
  7643.                
  7644.                 if (cfstreamThreadRetainCount == 0)
  7645.                 {
  7646.                         LogWarn(@"Logic error concerning cfstreamThread start / stop");
  7647.                         return_from_block;
  7648.                 }
  7649.                
  7650.                 if (--cfstreamThreadRetainCount == 0)
  7651.                 {
  7652.                         [cfstreamThread cancel]; // set isCancelled flag
  7653.                        
  7654.                         // wake up the thread
  7655.             [[self class] performSelector:@selector(ignore:)
  7656.                                  onThread:cfstreamThread
  7657.                                withObject:[NSNull null]
  7658.                             waitUntilDone:NO];
  7659.            
  7660.                         cfstreamThread = nil;
  7661.                 }
  7662.                
  7663.         #pragma clang diagnostic pop
  7664.         }});
  7665. }
  7666.  
  7667. + (void)cfstreamThread:(id)unused { @autoreleasepool
  7668. {
  7669.         [[NSThread currentThread] setName:GCDAsyncSocketThreadName];
  7670.        
  7671.         LogInfo(@"CFStreamThread: Started");
  7672.        
  7673.         // We can't run the run loop unless it has an associated input source or a timer.
  7674.         // So we'll just create a timer that will never fire - unless the server runs for decades.
  7675.         [NSTimer scheduledTimerWithTimeInterval:[[NSDate distantFuture] timeIntervalSinceNow]
  7676.                                          target:self
  7677.                                        selector:@selector(ignore:)
  7678.                                        userInfo:nil
  7679.                                         repeats:YES];
  7680.        
  7681.         NSThread *currentThread = [NSThread currentThread];
  7682.         NSRunLoop *currentRunLoop = [NSRunLoop currentRunLoop];
  7683.        
  7684.         BOOL isCancelled = [currentThread isCancelled];
  7685.        
  7686.         while (!isCancelled && [currentRunLoop runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]])
  7687.         {
  7688.                 isCancelled = [currentThread isCancelled];
  7689.         }
  7690.        
  7691.         LogInfo(@"CFStreamThread: Stopped");
  7692. }}
  7693.  
  7694. + (void)scheduleCFStreams:(GCDAsyncSocket *)asyncSocket
  7695. {
  7696.         LogTrace();
  7697.         NSAssert([NSThread currentThread] == cfstreamThread, @"Invoked on wrong thread");
  7698.        
  7699.         CFRunLoopRef runLoop = CFRunLoopGetCurrent();
  7700.        
  7701.         if (asyncSocket->readStream)
  7702.                 CFReadStreamScheduleWithRunLoop(asyncSocket->readStream, runLoop, kCFRunLoopDefaultMode);
  7703.        
  7704.         if (asyncSocket->writeStream)
  7705.                 CFWriteStreamScheduleWithRunLoop(asyncSocket->writeStream, runLoop, kCFRunLoopDefaultMode);
  7706. }
  7707.  
  7708. + (void)unscheduleCFStreams:(GCDAsyncSocket *)asyncSocket
  7709. {
  7710.         LogTrace();
  7711.         NSAssert([NSThread currentThread] == cfstreamThread, @"Invoked on wrong thread");
  7712.        
  7713.         CFRunLoopRef runLoop = CFRunLoopGetCurrent();
  7714.        
  7715.         if (asyncSocket->readStream)
  7716.                 CFReadStreamUnscheduleFromRunLoop(asyncSocket->readStream, runLoop, kCFRunLoopDefaultMode);
  7717.        
  7718.         if (asyncSocket->writeStream)
  7719.                 CFWriteStreamUnscheduleFromRunLoop(asyncSocket->writeStream, runLoop, kCFRunLoopDefaultMode);
  7720. }
  7721.  
  7722. static void CFReadStreamCallback (CFReadStreamRef stream, CFStreamEventType type, void *pInfo)
  7723. {
  7724.         GCDAsyncSocket *asyncSocket = (__bridge GCDAsyncSocket *)pInfo;
  7725.        
  7726.         switch(type)
  7727.         {
  7728.                 case kCFStreamEventHasBytesAvailable:
  7729.                 {
  7730.                         dispatch_async(asyncSocket->socketQueue, ^{ @autoreleasepool {
  7731.                                
  7732.                                 LogCVerbose(@"CFReadStreamCallback - HasBytesAvailable");
  7733.                                
  7734.                                 if (asyncSocket->readStream != stream)
  7735.                                         return_from_block;
  7736.                                
  7737.                                 if ((asyncSocket->flags & kStartingReadTLS) && (asyncSocket->flags & kStartingWriteTLS))
  7738.                                 {
  7739.                                         // If we set kCFStreamPropertySSLSettings before we opened the streams, this might be a lie.
  7740.                                         // (A callback related to the tcp stream, but not to the SSL layer).
  7741.                                        
  7742.                                         if (CFReadStreamHasBytesAvailable(asyncSocket->readStream))
  7743.                                         {
  7744.                                                 asyncSocket->flags |= kSecureSocketHasBytesAvailable;
  7745.                                                 [asyncSocket cf_finishSSLHandshake];
  7746.                                         }
  7747.                                 }
  7748.                                 else
  7749.                                 {
  7750.                                         asyncSocket->flags |= kSecureSocketHasBytesAvailable;
  7751.                                         [asyncSocket doReadData];
  7752.                                 }
  7753.                         }});
  7754.                        
  7755.                         break;
  7756.                 }
  7757.                 default:
  7758.                 {
  7759.                         NSError *error = (__bridge_transfer  NSError *)CFReadStreamCopyError(stream);
  7760.                        
  7761.                         if (error == nil && type == kCFStreamEventEndEncountered)
  7762.                         {
  7763.                                 error = [asyncSocket connectionClosedError];
  7764.                         }
  7765.                        
  7766.                         dispatch_async(asyncSocket->socketQueue, ^{ @autoreleasepool {
  7767.                                
  7768.                                 LogCVerbose(@"CFReadStreamCallback - Other");
  7769.                                
  7770.                                 if (asyncSocket->readStream != stream)
  7771.                                         return_from_block;
  7772.                                
  7773.                                 if ((asyncSocket->flags & kStartingReadTLS) && (asyncSocket->flags & kStartingWriteTLS))
  7774.                                 {
  7775.                                         [asyncSocket cf_abortSSLHandshake:error];
  7776.                                 }
  7777.                                 else
  7778.                                 {
  7779.                                         [asyncSocket closeWithError:error];
  7780.                                 }
  7781.                         }});
  7782.                        
  7783.                         break;
  7784.                 }
  7785.         }
  7786.        
  7787. }
  7788.  
  7789. static void CFWriteStreamCallback (CFWriteStreamRef stream, CFStreamEventType type, void *pInfo)
  7790. {
  7791.         GCDAsyncSocket *asyncSocket = (__bridge GCDAsyncSocket *)pInfo;
  7792.        
  7793.         switch(type)
  7794.         {
  7795.                 case kCFStreamEventCanAcceptBytes:
  7796.                 {
  7797.                         dispatch_async(asyncSocket->socketQueue, ^{ @autoreleasepool {
  7798.                                
  7799.                                 LogCVerbose(@"CFWriteStreamCallback - CanAcceptBytes");
  7800.                                
  7801.                                 if (asyncSocket->writeStream != stream)
  7802.                                         return_from_block;
  7803.                                
  7804.                                 if ((asyncSocket->flags & kStartingReadTLS) && (asyncSocket->flags & kStartingWriteTLS))
  7805.                                 {
  7806.                                         // If we set kCFStreamPropertySSLSettings before we opened the streams, this might be a lie.
  7807.                                         // (A callback related to the tcp stream, but not to the SSL layer).
  7808.                                        
  7809.                                         if (CFWriteStreamCanAcceptBytes(asyncSocket->writeStream))
  7810.                                         {
  7811.                                                 asyncSocket->flags |= kSocketCanAcceptBytes;
  7812.                                                 [asyncSocket cf_finishSSLHandshake];
  7813.                                         }
  7814.                                 }
  7815.                                 else
  7816.                                 {
  7817.                                         asyncSocket->flags |= kSocketCanAcceptBytes;
  7818.                                         [asyncSocket doWriteData];
  7819.                                 }
  7820.                         }});
  7821.                        
  7822.                         break;
  7823.                 }
  7824.                 default:
  7825.                 {
  7826.                         NSError *error = (__bridge_transfer NSError *)CFWriteStreamCopyError(stream);
  7827.                        
  7828.                         if (error == nil && type == kCFStreamEventEndEncountered)
  7829.                         {
  7830.                                 error = [asyncSocket connectionClosedError];
  7831.                         }
  7832.                        
  7833.                         dispatch_async(asyncSocket->socketQueue, ^{ @autoreleasepool {
  7834.                                
  7835.                                 LogCVerbose(@"CFWriteStreamCallback - Other");
  7836.                                
  7837.                                 if (asyncSocket->writeStream != stream)
  7838.                                         return_from_block;
  7839.                                
  7840.                                 if ((asyncSocket->flags & kStartingReadTLS) && (asyncSocket->flags & kStartingWriteTLS))
  7841.                                 {
  7842.                                         [asyncSocket cf_abortSSLHandshake:error];
  7843.                                 }
  7844.                                 else
  7845.                                 {
  7846.                                         [asyncSocket closeWithError:error];
  7847.                                 }
  7848.                         }});
  7849.                        
  7850.                         break;
  7851.                 }
  7852.         }
  7853.        
  7854. }
  7855.  
  7856. - (BOOL)createReadAndWriteStream
  7857. {
  7858.         LogTrace();
  7859.        
  7860.         NSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @"Must be dispatched on socketQueue");
  7861.        
  7862.        
  7863.         if (readStream || writeStream)
  7864.         {
  7865.                 // Streams already created
  7866.                 return YES;
  7867.         }
  7868.        
  7869.         int socketFD = (socket4FD != SOCKET_NULL) ? socket4FD : (socket6FD != SOCKET_NULL) ? socket6FD : socketUN;
  7870.        
  7871.         if (socketFD == SOCKET_NULL)
  7872.         {
  7873.                 // Cannot create streams without a file descriptor
  7874.                 return NO;
  7875.         }
  7876.        
  7877.         if (![self isConnected])
  7878.         {
  7879.                 // Cannot create streams until file descriptor is connected
  7880.                 return NO;
  7881.         }
  7882.        
  7883.         LogVerbose(@"Creating read and write stream...");
  7884.        
  7885.         CFStreamCreatePairWithSocket(NULL, (CFSocketNativeHandle)socketFD, &readStream, &writeStream);
  7886.        
  7887.         // The kCFStreamPropertyShouldCloseNativeSocket property should be false by default (for our case).
  7888.         // But let's not take any chances.
  7889.        
  7890.         if (readStream)
  7891.                 CFReadStreamSetProperty(readStream, kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanFalse);
  7892.         if (writeStream)
  7893.                 CFWriteStreamSetProperty(writeStream, kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanFalse);
  7894.        
  7895.         if ((readStream == NULL) || (writeStream == NULL))
  7896.         {
  7897.                 LogWarn(@"Unable to create read and write stream...");
  7898.                
  7899.                 if (readStream)
  7900.                 {
  7901.                         CFReadStreamClose(readStream);
  7902.                         CFRelease(readStream);
  7903.                         readStream = NULL;
  7904.                 }
  7905.                 if (writeStream)
  7906.                 {
  7907.                         CFWriteStreamClose(writeStream);
  7908.                         CFRelease(writeStream);
  7909.                         writeStream = NULL;
  7910.                 }
  7911.                
  7912.                 return NO;
  7913.         }
  7914.        
  7915.         return YES;
  7916. }
  7917.  
  7918. - (BOOL)registerForStreamCallbacksIncludingReadWrite:(BOOL)includeReadWrite
  7919. {
  7920.         LogVerbose(@"%@ %@", THIS_METHOD, (includeReadWrite ? @"YES" : @"NO"));
  7921.        
  7922.         NSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @"Must be dispatched on socketQueue");
  7923.         NSAssert((readStream != NULL && writeStream != NULL), @"Read/Write stream is null");
  7924.        
  7925.         streamContext.version = 0;
  7926.         streamContext.info = (__bridge void *)(self);
  7927.         streamContext.retain = nil;
  7928.         streamContext.release = nil;
  7929.         streamContext.copyDescription = nil;
  7930.        
  7931.         CFOptionFlags readStreamEvents = kCFStreamEventErrorOccurred | kCFStreamEventEndEncountered;
  7932.         if (includeReadWrite)
  7933.                 readStreamEvents |= kCFStreamEventHasBytesAvailable;
  7934.        
  7935.         if (!CFReadStreamSetClient(readStream, readStreamEvents, &CFReadStreamCallback, &streamContext))
  7936.         {
  7937.                 return NO;
  7938.         }
  7939.        
  7940.         CFOptionFlags writeStreamEvents = kCFStreamEventErrorOccurred | kCFStreamEventEndEncountered;
  7941.         if (includeReadWrite)
  7942.                 writeStreamEvents |= kCFStreamEventCanAcceptBytes;
  7943.        
  7944.         if (!CFWriteStreamSetClient(writeStream, writeStreamEvents, &CFWriteStreamCallback, &streamContext))
  7945.         {
  7946.                 return NO;
  7947.         }
  7948.        
  7949.         return YES;
  7950. }
  7951.  
  7952. - (BOOL)addStreamsToRunLoop
  7953. {
  7954.         LogTrace();
  7955.        
  7956.         NSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @"Must be dispatched on socketQueue");
  7957.         NSAssert((readStream != NULL && writeStream != NULL), @"Read/Write stream is null");
  7958.        
  7959.         if (!(flags & kAddedStreamsToRunLoop))
  7960.         {
  7961.                 LogVerbose(@"Adding streams to runloop...");
  7962.                
  7963.                 [[self class] startCFStreamThreadIfNeeded];
  7964.         dispatch_sync(cfstreamThreadSetupQueue, ^{
  7965.             [[self class] performSelector:@selector(scheduleCFStreams:)
  7966.                                  onThread:cfstreamThread
  7967.                                withObject:self
  7968.                             waitUntilDone:YES];
  7969.         });
  7970.                 flags |= kAddedStreamsToRunLoop;
  7971.         }
  7972.        
  7973.         return YES;
  7974. }
  7975.  
  7976. - (void)removeStreamsFromRunLoop
  7977. {
  7978.         LogTrace();
  7979.        
  7980.         NSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @"Must be dispatched on socketQueue");
  7981.         NSAssert((readStream != NULL && writeStream != NULL), @"Read/Write stream is null");
  7982.        
  7983.         if (flags & kAddedStreamsToRunLoop)
  7984.         {
  7985.                 LogVerbose(@"Removing streams from runloop...");
  7986.        
  7987.         dispatch_sync(cfstreamThreadSetupQueue, ^{
  7988.             [[self class] performSelector:@selector(unscheduleCFStreams:)
  7989.                                  onThread:cfstreamThread
  7990.                                withObject:self
  7991.                             waitUntilDone:YES];
  7992.         });
  7993.                 [[self class] stopCFStreamThreadIfNeeded];
  7994.                
  7995.                 flags &= ~kAddedStreamsToRunLoop;
  7996.         }
  7997. }
  7998.  
  7999. - (BOOL)openStreams
  8000. {
  8001.         LogTrace();
  8002.        
  8003.         NSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @"Must be dispatched on socketQueue");
  8004.         NSAssert((readStream != NULL && writeStream != NULL), @"Read/Write stream is null");
  8005.        
  8006.         CFStreamStatus readStatus = CFReadStreamGetStatus(readStream);
  8007.         CFStreamStatus writeStatus = CFWriteStreamGetStatus(writeStream);
  8008.        
  8009.         if ((readStatus == kCFStreamStatusNotOpen) || (writeStatus == kCFStreamStatusNotOpen))
  8010.         {
  8011.                 LogVerbose(@"Opening read and write stream...");
  8012.                
  8013.                 BOOL r1 = CFReadStreamOpen(readStream);
  8014.                 BOOL r2 = CFWriteStreamOpen(writeStream);
  8015.                
  8016.                 if (!r1 || !r2)
  8017.                 {
  8018.                         LogError(@"Error in CFStreamOpen");
  8019.                         return NO;
  8020.                 }
  8021.         }
  8022.        
  8023.         return YES;
  8024. }
  8025.  
  8026. #endif
  8027.  
  8028. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  8029. #pragma mark Advanced
  8030. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  8031.  
  8032. /**
  8033.  * See header file for big discussion of this method.
  8034. **/
  8035. - (BOOL)autoDisconnectOnClosedReadStream
  8036. {
  8037.         // Note: YES means kAllowHalfDuplexConnection is OFF
  8038.        
  8039.         if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
  8040.         {
  8041.                 return ((config & kAllowHalfDuplexConnection) == 0);
  8042.         }
  8043.         else
  8044.         {
  8045.                 __block BOOL result;
  8046.                
  8047.                 dispatch_sync(socketQueue, ^{
  8048.             result = ((self->config & kAllowHalfDuplexConnection) == 0);
  8049.                 });
  8050.                
  8051.                 return result;
  8052.         }
  8053. }
  8054.  
  8055. /**
  8056.  * See header file for big discussion of this method.
  8057. **/
  8058. - (void)setAutoDisconnectOnClosedReadStream:(BOOL)flag
  8059. {
  8060.         // Note: YES means kAllowHalfDuplexConnection is OFF
  8061.        
  8062.         dispatch_block_t block = ^{
  8063.                
  8064.                 if (flag)
  8065.             self->config &= ~kAllowHalfDuplexConnection;
  8066.                 else
  8067.             self->config |= kAllowHalfDuplexConnection;
  8068.         };
  8069.        
  8070.         if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
  8071.                 block();
  8072.         else
  8073.                 dispatch_async(socketQueue, block);
  8074. }
  8075.  
  8076.  
  8077. /**
  8078.  * See header file for big discussion of this method.
  8079. **/
  8080. - (void)markSocketQueueTargetQueue:(dispatch_queue_t)socketNewTargetQueue
  8081. {
  8082.         void *nonNullUnusedPointer = (__bridge void *)self;
  8083.         dispatch_queue_set_specific(socketNewTargetQueue, IsOnSocketQueueOrTargetQueueKey, nonNullUnusedPointer, NULL);
  8084. }
  8085.  
  8086. /**
  8087.  * See header file for big discussion of this method.
  8088. **/
  8089. - (void)unmarkSocketQueueTargetQueue:(dispatch_queue_t)socketOldTargetQueue
  8090. {
  8091.         dispatch_queue_set_specific(socketOldTargetQueue, IsOnSocketQueueOrTargetQueueKey, NULL, NULL);
  8092. }
  8093.  
  8094. /**
  8095.  * See header file for big discussion of this method.
  8096. **/
  8097. - (void)performBlock:(dispatch_block_t)block
  8098. {
  8099.         if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
  8100.                 block();
  8101.         else
  8102.                 dispatch_sync(socketQueue, block);
  8103. }
  8104.  
  8105. /**
  8106.  * Questions? Have you read the header file?
  8107. **/
  8108. - (int)socketFD
  8109. {
  8110.         if (!dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
  8111.         {
  8112.                 LogWarn(@"%@ - Method only available from within the context of a performBlock: invocation", THIS_METHOD);
  8113.                 return SOCKET_NULL;
  8114.         }
  8115.        
  8116.         if (socket4FD != SOCKET_NULL)
  8117.                 return socket4FD;
  8118.         else
  8119.                 return socket6FD;
  8120. }
  8121.  
  8122. /**
  8123.  * Questions? Have you read the header file?
  8124. **/
  8125. - (int)socket4FD
  8126. {
  8127.         if (!dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
  8128.         {
  8129.                 LogWarn(@"%@ - Method only available from within the context of a performBlock: invocation", THIS_METHOD);
  8130.                 return SOCKET_NULL;
  8131.         }
  8132.        
  8133.         return socket4FD;
  8134. }
  8135.  
  8136. /**
  8137.  * Questions? Have you read the header file?
  8138. **/
  8139. - (int)socket6FD
  8140. {
  8141.         if (!dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
  8142.         {
  8143.                 LogWarn(@"%@ - Method only available from within the context of a performBlock: invocation", THIS_METHOD);
  8144.                 return SOCKET_NULL;
  8145.         }
  8146.        
  8147.         return socket6FD;
  8148. }
  8149.  
  8150. #if TARGET_OS_IPHONE
  8151.  
  8152. /**
  8153.  * Questions? Have you read the header file?
  8154. **/
  8155. - (CFReadStreamRef)readStream
  8156. {
  8157.         if (!dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
  8158.         {
  8159.                 LogWarn(@"%@ - Method only available from within the context of a performBlock: invocation", THIS_METHOD);
  8160.                 return NULL;
  8161.         }
  8162.        
  8163.         if (readStream == NULL)
  8164.                 [self createReadAndWriteStream];
  8165.        
  8166.         return readStream;
  8167. }
  8168.  
  8169. /**
  8170.  * Questions? Have you read the header file?
  8171. **/
  8172. - (CFWriteStreamRef)writeStream
  8173. {
  8174.         if (!dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
  8175.         {
  8176.                 LogWarn(@"%@ - Method only available from within the context of a performBlock: invocation", THIS_METHOD);
  8177.                 return NULL;
  8178.         }
  8179.        
  8180.         if (writeStream == NULL)
  8181.                 [self createReadAndWriteStream];
  8182.        
  8183.         return writeStream;
  8184. }
  8185.  
  8186. - (BOOL)enableBackgroundingOnSocketWithCaveat:(BOOL)caveat
  8187. {
  8188.         if (![self createReadAndWriteStream])
  8189.         {
  8190.                 // Error occurred creating streams (perhaps socket isn't open)
  8191.                 return NO;
  8192.         }
  8193.        
  8194.         BOOL r1, r2;
  8195.        
  8196.         LogVerbose(@"Enabling backgrouding on socket");
  8197.        
  8198. #pragma clang diagnostic push
  8199. #pragma clang diagnostic ignored "-Wdeprecated-declarations"
  8200.         r1 = CFReadStreamSetProperty(readStream, kCFStreamNetworkServiceType, kCFStreamNetworkServiceTypeVoIP);
  8201.         r2 = CFWriteStreamSetProperty(writeStream, kCFStreamNetworkServiceType, kCFStreamNetworkServiceTypeVoIP);
  8202. #pragma clang diagnostic pop
  8203.  
  8204.         if (!r1 || !r2)
  8205.         {
  8206.                 return NO;
  8207.         }
  8208.        
  8209.         if (!caveat)
  8210.         {
  8211.                 if (![self openStreams])
  8212.                 {
  8213.                         return NO;
  8214.                 }
  8215.         }
  8216.        
  8217.         return YES;
  8218. }
  8219.  
  8220. /**
  8221.  * Questions? Have you read the header file?
  8222. **/
  8223. - (BOOL)enableBackgroundingOnSocket
  8224. {
  8225.         LogTrace();
  8226.        
  8227.         if (!dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
  8228.         {
  8229.                 LogWarn(@"%@ - Method only available from within the context of a performBlock: invocation", THIS_METHOD);
  8230.                 return NO;
  8231.         }
  8232.        
  8233.         return [self enableBackgroundingOnSocketWithCaveat:NO];
  8234. }
  8235.  
  8236. - (BOOL)enableBackgroundingOnSocketWithCaveat // Deprecated in iOS 4.???
  8237. {
  8238.         // This method was created as a workaround for a bug in iOS.
  8239.         // Apple has since fixed this bug.
  8240.         // I'm not entirely sure which version of iOS they fixed it in...
  8241.        
  8242.         LogTrace();
  8243.        
  8244.         if (!dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
  8245.         {
  8246.                 LogWarn(@"%@ - Method only available from within the context of a performBlock: invocation", THIS_METHOD);
  8247.                 return NO;
  8248.         }
  8249.        
  8250.         return [self enableBackgroundingOnSocketWithCaveat:YES];
  8251. }
  8252.  
  8253. #endif
  8254.  
  8255. - (SSLContextRef)sslContext
  8256. {
  8257.         if (!dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
  8258.         {
  8259.                 LogWarn(@"%@ - Method only available from within the context of a performBlock: invocation", THIS_METHOD);
  8260.                 return NULL;
  8261.         }
  8262.        
  8263.         return sslContext;
  8264. }
  8265.  
  8266. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  8267. #pragma mark Class Utilities
  8268. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  8269.  
  8270. + (NSMutableArray *)lookupHost:(NSString *)host port:(uint16_t)port error:(NSError **)errPtr
  8271. {
  8272.         LogTrace();
  8273.        
  8274.         NSMutableArray *addresses = nil;
  8275.         NSError *error = nil;
  8276.        
  8277.         if ([host isEqualToString:@"localhost"] || [host isEqualToString:@"loopback"])
  8278.         {
  8279.                 // Use LOOPBACK address
  8280.                 struct sockaddr_in nativeAddr4;
  8281.                 nativeAddr4.sin_len         = sizeof(struct sockaddr_in);
  8282.                 nativeAddr4.sin_family      = AF_INET;
  8283.                 nativeAddr4.sin_port        = htons(port);
  8284.                 nativeAddr4.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
  8285.                 memset(&(nativeAddr4.sin_zero), 0, sizeof(nativeAddr4.sin_zero));
  8286.                
  8287.                 struct sockaddr_in6 nativeAddr6;
  8288.                 nativeAddr6.sin6_len        = sizeof(struct sockaddr_in6);
  8289.                 nativeAddr6.sin6_family     = AF_INET6;
  8290.                 nativeAddr6.sin6_port       = htons(port);
  8291.                 nativeAddr6.sin6_flowinfo   = 0;
  8292.                 nativeAddr6.sin6_addr       = in6addr_loopback;
  8293.                 nativeAddr6.sin6_scope_id   = 0;
  8294.                
  8295.                 // Wrap the native address structures
  8296.                
  8297.                 NSData *address4 = [NSData dataWithBytes:&nativeAddr4 length:sizeof(nativeAddr4)];
  8298.                 NSData *address6 = [NSData dataWithBytes:&nativeAddr6 length:sizeof(nativeAddr6)];
  8299.                
  8300.                 addresses = [NSMutableArray arrayWithCapacity:2];
  8301.                 [addresses addObject:address4];
  8302.                 [addresses addObject:address6];
  8303.         }
  8304.         else
  8305.         {
  8306.                 NSString *portStr = [NSString stringWithFormat:@"%hu", port];
  8307.                
  8308.                 struct addrinfo hints, *res, *res0;
  8309.                
  8310.                 memset(&hints, 0, sizeof(hints));
  8311.                 hints.ai_family   = PF_UNSPEC;
  8312.                 hints.ai_socktype = SOCK_STREAM;
  8313.                 hints.ai_protocol = IPPROTO_TCP;
  8314.                
  8315.                 int gai_error = getaddrinfo([host UTF8String], [portStr UTF8String], &hints, &res0);
  8316.                
  8317.                 if (gai_error)
  8318.                 {
  8319.                         error = [self gaiError:gai_error];
  8320.                 }
  8321.                 else
  8322.                 {
  8323.                         NSUInteger capacity = 0;
  8324.                         for (res = res0; res; res = res->ai_next)
  8325.                         {
  8326.                                 if (res->ai_family == AF_INET || res->ai_family == AF_INET6) {
  8327.                                         capacity++;
  8328.                                 }
  8329.                         }
  8330.                        
  8331.                         addresses = [NSMutableArray arrayWithCapacity:capacity];
  8332.                        
  8333.                         for (res = res0; res; res = res->ai_next)
  8334.                         {
  8335.                                 if (res->ai_family == AF_INET)
  8336.                                 {
  8337.                                         // Found IPv4 address.
  8338.                                         // Wrap the native address structure, and add to results.
  8339.                                        
  8340.                                         NSData *address4 = [NSData dataWithBytes:res->ai_addr length:res->ai_addrlen];
  8341.                                         [addresses addObject:address4];
  8342.                                 }
  8343.                                 else if (res->ai_family == AF_INET6)
  8344.                                 {
  8345.                                         // Fixes connection issues with IPv6
  8346.                                         // https://github.com/robbiehanson/CocoaAsyncSocket/issues/429#issuecomment-222477158
  8347.                                        
  8348.                                         // Found IPv6 address.
  8349.                                         // Wrap the native address structure, and add to results.
  8350.                                        
  8351.                                         struct sockaddr_in6 *sockaddr = (struct sockaddr_in6 *)(void *)res->ai_addr;
  8352.                                         in_port_t *portPtr = &sockaddr->sin6_port;
  8353.                                         if ((portPtr != NULL) && (*portPtr == 0)) {
  8354.                                                 *portPtr = htons(port);
  8355.                                         }
  8356.  
  8357.                                         NSData *address6 = [NSData dataWithBytes:res->ai_addr length:res->ai_addrlen];
  8358.                                         [addresses addObject:address6];
  8359.                                 }
  8360.                         }
  8361.                         freeaddrinfo(res0);
  8362.                        
  8363.                         if ([addresses count] == 0)
  8364.                         {
  8365.                                 error = [self gaiError:EAI_FAIL];
  8366.                         }
  8367.                 }
  8368.         }
  8369.        
  8370.         if (errPtr) *errPtr = error;
  8371.         return addresses;
  8372. }
  8373.  
  8374. + (NSString *)hostFromSockaddr4:(const struct sockaddr_in *)pSockaddr4
  8375. {
  8376.         char addrBuf[INET_ADDRSTRLEN];
  8377.        
  8378.         if (inet_ntop(AF_INET, &pSockaddr4->sin_addr, addrBuf, (socklen_t)sizeof(addrBuf)) == NULL)
  8379.         {
  8380.                 addrBuf[0] = '\0';
  8381.         }
  8382.        
  8383.         return [NSString stringWithCString:addrBuf encoding:NSASCIIStringEncoding];
  8384. }
  8385.  
  8386. + (NSString *)hostFromSockaddr6:(const struct sockaddr_in6 *)pSockaddr6
  8387. {
  8388.         char addrBuf[INET6_ADDRSTRLEN];
  8389.        
  8390.         if (inet_ntop(AF_INET6, &pSockaddr6->sin6_addr, addrBuf, (socklen_t)sizeof(addrBuf)) == NULL)
  8391.         {
  8392.                 addrBuf[0] = '\0';
  8393.         }
  8394.        
  8395.         return [NSString stringWithCString:addrBuf encoding:NSASCIIStringEncoding];
  8396. }
  8397.  
  8398. + (uint16_t)portFromSockaddr4:(const struct sockaddr_in *)pSockaddr4
  8399. {
  8400.         return ntohs(pSockaddr4->sin_port);
  8401. }
  8402.  
  8403. + (uint16_t)portFromSockaddr6:(const struct sockaddr_in6 *)pSockaddr6
  8404. {
  8405.         return ntohs(pSockaddr6->sin6_port);
  8406. }
  8407.  
  8408. + (NSURL *)urlFromSockaddrUN:(const struct sockaddr_un *)pSockaddr
  8409. {
  8410.         NSString *path = [NSString stringWithUTF8String:pSockaddr->sun_path];
  8411.         return [NSURL fileURLWithPath:path];
  8412. }
  8413.  
  8414. + (NSString *)hostFromAddress:(NSData *)address
  8415. {
  8416.         NSString *host;
  8417.        
  8418.         if ([self getHost:&host port:NULL fromAddress:address])
  8419.                 return host;
  8420.         else
  8421.                 return nil;
  8422. }
  8423.  
  8424. + (uint16_t)portFromAddress:(NSData *)address
  8425. {
  8426.         uint16_t port;
  8427.        
  8428.         if ([self getHost:NULL port:&port fromAddress:address])
  8429.                 return port;
  8430.         else
  8431.                 return 0;
  8432. }
  8433.  
  8434. + (BOOL)isIPv4Address:(NSData *)address
  8435. {
  8436.         if ([address length] >= sizeof(struct sockaddr))
  8437.         {
  8438.                 const struct sockaddr *sockaddrX = [address bytes];
  8439.                
  8440.                 if (sockaddrX->sa_family == AF_INET) {
  8441.                         return YES;
  8442.                 }
  8443.         }
  8444.        
  8445.         return NO;
  8446. }
  8447.  
  8448. + (BOOL)isIPv6Address:(NSData *)address
  8449. {
  8450.         if ([address length] >= sizeof(struct sockaddr))
  8451.         {
  8452.                 const struct sockaddr *sockaddrX = [address bytes];
  8453.                
  8454.                 if (sockaddrX->sa_family == AF_INET6) {
  8455.                         return YES;
  8456.                 }
  8457.         }
  8458.        
  8459.         return NO;
  8460. }
  8461.  
  8462. + (BOOL)getHost:(NSString **)hostPtr port:(uint16_t *)portPtr fromAddress:(NSData *)address
  8463. {
  8464.         return [self getHost:hostPtr port:portPtr family:NULL fromAddress:address];
  8465. }
  8466.  
  8467. + (BOOL)getHost:(NSString **)hostPtr port:(uint16_t *)portPtr family:(sa_family_t *)afPtr fromAddress:(NSData *)address
  8468. {
  8469.         if ([address length] >= sizeof(struct sockaddr))
  8470.         {
  8471.                 const struct sockaddr *sockaddrX = [address bytes];
  8472.                
  8473.                 if (sockaddrX->sa_family == AF_INET)
  8474.                 {
  8475.                         if ([address length] >= sizeof(struct sockaddr_in))
  8476.                         {
  8477.                                 struct sockaddr_in sockaddr4;
  8478.                                 memcpy(&sockaddr4, sockaddrX, sizeof(sockaddr4));
  8479.                                
  8480.                                 if (hostPtr) *hostPtr = [self hostFromSockaddr4:&sockaddr4];
  8481.                                 if (portPtr) *portPtr = [self portFromSockaddr4:&sockaddr4];
  8482.                                 if (afPtr)   *afPtr   = AF_INET;
  8483.                                
  8484.                                 return YES;
  8485.                         }
  8486.                 }
  8487.                 else if (sockaddrX->sa_family == AF_INET6)
  8488.                 {
  8489.                         if ([address length] >= sizeof(struct sockaddr_in6))
  8490.                         {
  8491.                                 struct sockaddr_in6 sockaddr6;
  8492.                                 memcpy(&sockaddr6, sockaddrX, sizeof(sockaddr6));
  8493.                                
  8494.                                 if (hostPtr) *hostPtr = [self hostFromSockaddr6:&sockaddr6];
  8495.                                 if (portPtr) *portPtr = [self portFromSockaddr6:&sockaddr6];
  8496.                                 if (afPtr)   *afPtr   = AF_INET6;
  8497.                                
  8498.                                 return YES;
  8499.                         }
  8500.                 }
  8501.         }
  8502.        
  8503.         return NO;
  8504. }
  8505.  
  8506. + (NSData *)CRLFData
  8507. {
  8508.         return [NSData dataWithBytes:"\x0D\x0A" length:2];
  8509. }
  8510.  
  8511. + (NSData *)CRData
  8512. {
  8513.         return [NSData dataWithBytes:"\x0D" length:1];
  8514. }
  8515.  
  8516. + (NSData *)LFData
  8517. {
  8518.         return [NSData dataWithBytes:"\x0A" length:1];
  8519. }
  8520.  
  8521. + (NSData *)ZeroData
  8522. {
  8523.         return [NSData dataWithBytes:"" length:1];
  8524. }
  8525.  
  8526. @end   
  8527.