PageRenderTime 63ms CodeModel.GetById 27ms RepoModel.GetById 0ms app.codeStats 1ms

/Pods/CocoaAsyncSocket/GCD/GCDAsyncSocket.m

https://gitlab.com/mba811/tokaidoapp
Objective C | 7825 lines | 5189 code | 1691 blank | 945 comment | 1158 complexity | 1d291c75e68fd0db60f37271abe308b7 MD5 | raw file
Possible License(s): BSD-3-Clause

Large files files are truncated, but you can click here to view the full file

  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. #import "GCDAsyncSocket.h"
  11. #if TARGET_OS_IPHONE
  12. #import <CFNetwork/CFNetwork.h>
  13. #endif
  14. #import <arpa/inet.h>
  15. #import <fcntl.h>
  16. #import <ifaddrs.h>
  17. #import <netdb.h>
  18. #import <netinet/in.h>
  19. #import <net/if.h>
  20. #import <sys/socket.h>
  21. #import <sys/types.h>
  22. #import <sys/ioctl.h>
  23. #import <sys/poll.h>
  24. #import <sys/uio.h>
  25. #import <sys/un.h>
  26. #import <unistd.h>
  27. #if ! __has_feature(objc_arc)
  28. #warning This file must be compiled with ARC. Use -fobjc-arc flag (or convert project to ARC).
  29. // For more information see: https://github.com/robbiehanson/CocoaAsyncSocket/wiki/ARC
  30. #endif
  31. /**
  32. * Does ARC support support GCD objects?
  33. * It does if the minimum deployment target is iOS 6+ or Mac OS X 10.8+
  34. **/
  35. #if TARGET_OS_IPHONE
  36. // Compiling for iOS
  37. #if __IPHONE_OS_VERSION_MIN_REQUIRED >= 60000 // iOS 6.0 or later
  38. #define NEEDS_DISPATCH_RETAIN_RELEASE 0
  39. #else // iOS 5.X or earlier
  40. #define NEEDS_DISPATCH_RETAIN_RELEASE 1
  41. #endif
  42. #else
  43. // Compiling for Mac OS X
  44. #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1080 // Mac OS X 10.8 or later
  45. #define NEEDS_DISPATCH_RETAIN_RELEASE 0
  46. #else
  47. #define NEEDS_DISPATCH_RETAIN_RELEASE 1 // Mac OS X 10.7 or earlier
  48. #endif
  49. #endif
  50. #if 0
  51. // Logging Enabled - See log level below
  52. // Logging uses the CocoaLumberjack framework (which is also GCD based).
  53. // https://github.com/robbiehanson/CocoaLumberjack
  54. //
  55. // It allows us to do a lot of logging without significantly slowing down the code.
  56. #import "DDLog.h"
  57. #define LogAsync YES
  58. #define LogContext 65535
  59. #define LogObjc(flg, frmt, ...) LOG_OBJC_MAYBE(LogAsync, logLevel, flg, LogContext, frmt, ##__VA_ARGS__)
  60. #define LogC(flg, frmt, ...) LOG_C_MAYBE(LogAsync, logLevel, flg, LogContext, frmt, ##__VA_ARGS__)
  61. #define LogError(frmt, ...) LogObjc(LOG_FLAG_ERROR, (@"%@: " frmt), THIS_FILE, ##__VA_ARGS__)
  62. #define LogWarn(frmt, ...) LogObjc(LOG_FLAG_WARN, (@"%@: " frmt), THIS_FILE, ##__VA_ARGS__)
  63. #define LogInfo(frmt, ...) LogObjc(LOG_FLAG_INFO, (@"%@: " frmt), THIS_FILE, ##__VA_ARGS__)
  64. #define LogVerbose(frmt, ...) LogObjc(LOG_FLAG_VERBOSE, (@"%@: " frmt), THIS_FILE, ##__VA_ARGS__)
  65. #define LogCError(frmt, ...) LogC(LOG_FLAG_ERROR, (@"%@: " frmt), THIS_FILE, ##__VA_ARGS__)
  66. #define LogCWarn(frmt, ...) LogC(LOG_FLAG_WARN, (@"%@: " frmt), THIS_FILE, ##__VA_ARGS__)
  67. #define LogCInfo(frmt, ...) LogC(LOG_FLAG_INFO, (@"%@: " frmt), THIS_FILE, ##__VA_ARGS__)
  68. #define LogCVerbose(frmt, ...) LogC(LOG_FLAG_VERBOSE, (@"%@: " frmt), THIS_FILE, ##__VA_ARGS__)
  69. #define LogTrace() LogObjc(LOG_FLAG_VERBOSE, @"%@: %@", THIS_FILE, THIS_METHOD)
  70. #define LogCTrace() LogC(LOG_FLAG_VERBOSE, @"%@: %s", THIS_FILE, __FUNCTION__)
  71. // Log levels : off, error, warn, info, verbose
  72. static const int logLevel = LOG_LEVEL_VERBOSE;
  73. #else
  74. // Logging Disabled
  75. #define LogError(frmt, ...) {}
  76. #define LogWarn(frmt, ...) {}
  77. #define LogInfo(frmt, ...) {}
  78. #define LogVerbose(frmt, ...) {}
  79. #define LogCError(frmt, ...) {}
  80. #define LogCWarn(frmt, ...) {}
  81. #define LogCInfo(frmt, ...) {}
  82. #define LogCVerbose(frmt, ...) {}
  83. #define LogTrace() {}
  84. #define LogCTrace(frmt, ...) {}
  85. #endif
  86. /**
  87. * Seeing a return statements within an inner block
  88. * can sometimes be mistaken for a return point of the enclosing method.
  89. * This makes inline blocks a bit easier to read.
  90. **/
  91. #define return_from_block return
  92. /**
  93. * A socket file descriptor is really just an integer.
  94. * It represents the index of the socket within the kernel.
  95. * This makes invalid file descriptor comparisons easier to read.
  96. **/
  97. #define SOCKET_NULL -1
  98. NSString *const GCDAsyncSocketException = @"GCDAsyncSocketException";
  99. NSString *const GCDAsyncSocketErrorDomain = @"GCDAsyncSocketErrorDomain";
  100. NSString *const GCDAsyncSocketQueueName = @"GCDAsyncSocket";
  101. NSString *const GCDAsyncSocketThreadName = @"GCDAsyncSocket-CFStream";
  102. #if SECURE_TRANSPORT_MAYBE_AVAILABLE
  103. NSString *const GCDAsyncSocketSSLCipherSuites = @"GCDAsyncSocketSSLCipherSuites";
  104. #if TARGET_OS_IPHONE
  105. NSString *const GCDAsyncSocketSSLProtocolVersionMin = @"GCDAsyncSocketSSLProtocolVersionMin";
  106. NSString *const GCDAsyncSocketSSLProtocolVersionMax = @"GCDAsyncSocketSSLProtocolVersionMax";
  107. #else
  108. NSString *const GCDAsyncSocketSSLDiffieHellmanParameters = @"GCDAsyncSocketSSLDiffieHellmanParameters";
  109. #endif
  110. #endif
  111. enum GCDAsyncSocketFlags
  112. {
  113. kSocketStarted = 1 << 0, // If set, socket has been started (accepting/connecting)
  114. kConnected = 1 << 1, // If set, the socket is connected
  115. kForbidReadsWrites = 1 << 2, // If set, no new reads or writes are allowed
  116. kReadsPaused = 1 << 3, // If set, reads are paused due to possible timeout
  117. kWritesPaused = 1 << 4, // If set, writes are paused due to possible timeout
  118. kDisconnectAfterReads = 1 << 5, // If set, disconnect after no more reads are queued
  119. kDisconnectAfterWrites = 1 << 6, // If set, disconnect after no more writes are queued
  120. kSocketCanAcceptBytes = 1 << 7, // If set, we know socket can accept bytes. If unset, it's unknown.
  121. kReadSourceSuspended = 1 << 8, // If set, the read source is suspended
  122. kWriteSourceSuspended = 1 << 9, // If set, the write source is suspended
  123. kQueuedTLS = 1 << 10, // If set, we've queued an upgrade to TLS
  124. kStartingReadTLS = 1 << 11, // If set, we're waiting for TLS negotiation to complete
  125. kStartingWriteTLS = 1 << 12, // If set, we're waiting for TLS negotiation to complete
  126. kSocketSecure = 1 << 13, // If set, socket is using secure communication via SSL/TLS
  127. kSocketHasReadEOF = 1 << 14, // If set, we have read EOF from socket
  128. kReadStreamClosed = 1 << 15, // If set, we've read EOF plus prebuffer has been drained
  129. #if TARGET_OS_IPHONE
  130. kAddedStreamsToRunLoop = 1 << 16, // If set, CFStreams have been added to listener thread
  131. kUsingCFStreamForTLS = 1 << 17, // If set, we're forced to use CFStream instead of SecureTransport
  132. kSecureSocketHasBytesAvailable = 1 << 18, // If set, CFReadStream has notified us of bytes available
  133. #endif
  134. };
  135. enum GCDAsyncSocketConfig
  136. {
  137. kIPv4Disabled = 1 << 0, // If set, IPv4 is disabled
  138. kIPv6Disabled = 1 << 1, // If set, IPv6 is disabled
  139. kPreferIPv6 = 1 << 2, // If set, IPv6 is preferred over IPv4
  140. kAllowHalfDuplexConnection = 1 << 3, // If set, the socket will stay open even if the read stream closes
  141. };
  142. #if TARGET_OS_IPHONE
  143. static NSThread *cfstreamThread; // Used for CFStreams
  144. #endif
  145. @interface GCDAsyncSocket (Private)
  146. // Accepting
  147. - (BOOL)doAccept:(int)socketFD;
  148. // Connecting
  149. - (void)startConnectTimeout:(NSTimeInterval)timeout;
  150. - (void)endConnectTimeout;
  151. - (void)doConnectTimeout;
  152. - (void)lookup:(int)aConnectIndex host:(NSString *)host port:(uint16_t)port;
  153. - (void)lookup:(int)aConnectIndex didSucceedWithAddress4:(NSData *)address4 address6:(NSData *)address6;
  154. - (void)lookup:(int)aConnectIndex didFail:(NSError *)error;
  155. - (BOOL)connectWithAddress4:(NSData *)address4 address6:(NSData *)address6 error:(NSError **)errPtr;
  156. - (BOOL)connectWithAddressUN:(NSData *)address error:(NSError **)errPtr;
  157. - (void)didConnect:(int)aConnectIndex;
  158. - (void)didNotConnect:(int)aConnectIndex error:(NSError *)error;
  159. // Disconnect
  160. - (void)closeWithError:(NSError *)error;
  161. - (void)close;
  162. - (void)maybeClose;
  163. // Errors
  164. - (NSError *)badConfigError:(NSString *)msg;
  165. - (NSError *)badParamError:(NSString *)msg;
  166. - (NSError *)gaiError:(int)gai_error;
  167. - (NSError *)errnoError;
  168. - (NSError *)errnoErrorWithReason:(NSString *)reason;
  169. - (NSError *)connectTimeoutError;
  170. - (NSError *)otherError:(NSString *)msg;
  171. // Diagnostics
  172. - (NSString *)connectedHost4;
  173. - (NSString *)connectedHost6;
  174. - (uint16_t)connectedPort4;
  175. - (uint16_t)connectedPort6;
  176. - (NSString *)localHost4;
  177. - (NSString *)localHost6;
  178. - (uint16_t)localPort4;
  179. - (uint16_t)localPort6;
  180. - (NSString *)connectedHostFromSocket4:(int)socketFD;
  181. - (NSString *)connectedHostFromSocket6:(int)socketFD;
  182. - (uint16_t)connectedPortFromSocket4:(int)socketFD;
  183. - (uint16_t)connectedPortFromSocket6:(int)socketFD;
  184. - (NSURL *)connectedUrlFromSocketUN:(int)socketFD;
  185. - (NSString *)localHostFromSocket4:(int)socketFD;
  186. - (NSString *)localHostFromSocket6:(int)socketFD;
  187. - (uint16_t)localPortFromSocket4:(int)socketFD;
  188. - (uint16_t)localPortFromSocket6:(int)socketFD;
  189. // Utilities
  190. - (void)getInterfaceAddress4:(NSMutableData **)addr4Ptr
  191. address6:(NSMutableData **)addr6Ptr
  192. fromDescription:(NSString *)interfaceDescription
  193. port:(uint16_t)port;
  194. - (NSData *)getInterfaceAddressFromUrl:(NSURL *)url;
  195. - (void)setupReadAndWriteSourcesForNewlyConnectedSocket:(int)socketFD;
  196. - (void)suspendReadSource;
  197. - (void)resumeReadSource;
  198. - (void)suspendWriteSource;
  199. - (void)resumeWriteSource;
  200. // Reading
  201. - (void)maybeDequeueRead;
  202. - (void)flushSSLBuffers;
  203. - (void)doReadData;
  204. - (void)doReadEOF;
  205. - (void)completeCurrentRead;
  206. - (void)endCurrentRead;
  207. - (void)setupReadTimerWithTimeout:(NSTimeInterval)timeout;
  208. - (void)doReadTimeout;
  209. - (void)doReadTimeoutWithExtension:(NSTimeInterval)timeoutExtension;
  210. // Writing
  211. - (void)maybeDequeueWrite;
  212. - (void)doWriteData;
  213. - (void)completeCurrentWrite;
  214. - (void)endCurrentWrite;
  215. - (void)setupWriteTimerWithTimeout:(NSTimeInterval)timeout;
  216. - (void)doWriteTimeout;
  217. - (void)doWriteTimeoutWithExtension:(NSTimeInterval)timeoutExtension;
  218. // Security
  219. - (void)maybeStartTLS;
  220. #if SECURE_TRANSPORT_MAYBE_AVAILABLE
  221. - (void)ssl_startTLS;
  222. - (void)ssl_continueSSLHandshake;
  223. #endif
  224. #if TARGET_OS_IPHONE
  225. - (void)cf_startTLS;
  226. #endif
  227. // CFStream
  228. #if TARGET_OS_IPHONE
  229. + (void)startCFStreamThreadIfNeeded;
  230. - (BOOL)createReadAndWriteStream;
  231. - (BOOL)registerForStreamCallbacksIncludingReadWrite:(BOOL)includeReadWrite;
  232. - (BOOL)addStreamsToRunLoop;
  233. - (BOOL)openStreams;
  234. - (void)removeStreamsFromRunLoop;
  235. #endif
  236. // Class Methods
  237. + (NSString *)hostFromSockaddr4:(const struct sockaddr_in *)pSockaddr4;
  238. + (NSString *)hostFromSockaddr6:(const struct sockaddr_in6 *)pSockaddr6;
  239. + (uint16_t)portFromSockaddr4:(const struct sockaddr_in *)pSockaddr4;
  240. + (uint16_t)portFromSockaddr6:(const struct sockaddr_in6 *)pSockaddr6;
  241. + (NSURL *)urlFromSockaddrUN:(const struct sockaddr_un *)pSockaddr;
  242. @end
  243. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  244. #pragma mark -
  245. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  246. /**
  247. * A PreBuffer is used when there is more data available on the socket
  248. * than is being requested by current read request.
  249. * In this case we slurp up all data from the socket (to minimize sys calls),
  250. * and store additional yet unread data in a "prebuffer".
  251. *
  252. * The prebuffer is entirely drained before we read from the socket again.
  253. * In other words, a large chunk of data is written is written to the prebuffer.
  254. * The prebuffer is then drained via a series of one or more reads (for subsequent read request(s)).
  255. *
  256. * A ring buffer was once used for this purpose.
  257. * But a ring buffer takes up twice as much memory as needed (double the size for mirroring).
  258. * In fact, it generally takes up more than twice the needed size as everything has to be rounded up to vm_page_size.
  259. * And since the prebuffer is always completely drained after being written to, a full ring buffer isn't needed.
  260. *
  261. * The current design is very simple and straight-forward, while also keeping memory requirements lower.
  262. **/
  263. @interface GCDAsyncSocketPreBuffer : NSObject
  264. {
  265. uint8_t *preBuffer;
  266. size_t preBufferSize;
  267. uint8_t *readPointer;
  268. uint8_t *writePointer;
  269. }
  270. - (id)initWithCapacity:(size_t)numBytes;
  271. - (void)ensureCapacityForWrite:(size_t)numBytes;
  272. - (size_t)availableBytes;
  273. - (uint8_t *)readBuffer;
  274. - (void)getReadBuffer:(uint8_t **)bufferPtr availableBytes:(size_t *)availableBytesPtr;
  275. - (size_t)availableSpace;
  276. - (uint8_t *)writeBuffer;
  277. - (void)getWriteBuffer:(uint8_t **)bufferPtr availableSpace:(size_t *)availableSpacePtr;
  278. - (void)didRead:(size_t)bytesRead;
  279. - (void)didWrite:(size_t)bytesWritten;
  280. - (void)reset;
  281. @end
  282. @implementation GCDAsyncSocketPreBuffer
  283. - (id)initWithCapacity:(size_t)numBytes
  284. {
  285. if ((self = [super init]))
  286. {
  287. preBufferSize = numBytes;
  288. preBuffer = malloc(preBufferSize);
  289. readPointer = preBuffer;
  290. writePointer = preBuffer;
  291. }
  292. return self;
  293. }
  294. - (void)dealloc
  295. {
  296. if (preBuffer)
  297. free(preBuffer);
  298. }
  299. - (void)ensureCapacityForWrite:(size_t)numBytes
  300. {
  301. size_t availableSpace = preBufferSize - (writePointer - readPointer);
  302. if (numBytes > availableSpace)
  303. {
  304. size_t additionalBytes = numBytes - availableSpace;
  305. size_t newPreBufferSize = preBufferSize + additionalBytes;
  306. uint8_t *newPreBuffer = realloc(preBuffer, newPreBufferSize);
  307. size_t readPointerOffset = readPointer - preBuffer;
  308. size_t writePointerOffset = writePointer - preBuffer;
  309. preBuffer = newPreBuffer;
  310. preBufferSize = newPreBufferSize;
  311. readPointer = preBuffer + readPointerOffset;
  312. writePointer = preBuffer + writePointerOffset;
  313. }
  314. }
  315. - (size_t)availableBytes
  316. {
  317. return writePointer - readPointer;
  318. }
  319. - (uint8_t *)readBuffer
  320. {
  321. return readPointer;
  322. }
  323. - (void)getReadBuffer:(uint8_t **)bufferPtr availableBytes:(size_t *)availableBytesPtr
  324. {
  325. if (bufferPtr) *bufferPtr = readPointer;
  326. if (availableBytesPtr) *availableBytesPtr = writePointer - readPointer;
  327. }
  328. - (void)didRead:(size_t)bytesRead
  329. {
  330. readPointer += bytesRead;
  331. if (readPointer == writePointer)
  332. {
  333. // The prebuffer has been drained. Reset pointers.
  334. readPointer = preBuffer;
  335. writePointer = preBuffer;
  336. }
  337. }
  338. - (size_t)availableSpace
  339. {
  340. return preBufferSize - (writePointer - readPointer);
  341. }
  342. - (uint8_t *)writeBuffer
  343. {
  344. return writePointer;
  345. }
  346. - (void)getWriteBuffer:(uint8_t **)bufferPtr availableSpace:(size_t *)availableSpacePtr
  347. {
  348. if (bufferPtr) *bufferPtr = writePointer;
  349. if (availableSpacePtr) *availableSpacePtr = preBufferSize - (writePointer - readPointer);
  350. }
  351. - (void)didWrite:(size_t)bytesWritten
  352. {
  353. writePointer += bytesWritten;
  354. }
  355. - (void)reset
  356. {
  357. readPointer = preBuffer;
  358. writePointer = preBuffer;
  359. }
  360. @end
  361. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  362. #pragma mark -
  363. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  364. /**
  365. * The GCDAsyncReadPacket encompasses the instructions for any given read.
  366. * The content of a read packet allows the code to determine if we're:
  367. * - reading to a certain length
  368. * - reading to a certain separator
  369. * - or simply reading the first chunk of available data
  370. **/
  371. @interface GCDAsyncReadPacket : NSObject
  372. {
  373. @public
  374. NSMutableData *buffer;
  375. NSUInteger startOffset;
  376. NSUInteger bytesDone;
  377. NSUInteger maxLength;
  378. NSTimeInterval timeout;
  379. NSUInteger readLength;
  380. NSData *term;
  381. BOOL bufferOwner;
  382. NSUInteger originalBufferLength;
  383. long tag;
  384. }
  385. - (id)initWithData:(NSMutableData *)d
  386. startOffset:(NSUInteger)s
  387. maxLength:(NSUInteger)m
  388. timeout:(NSTimeInterval)t
  389. readLength:(NSUInteger)l
  390. terminator:(NSData *)e
  391. tag:(long)i;
  392. - (void)ensureCapacityForAdditionalDataOfLength:(NSUInteger)bytesToRead;
  393. - (NSUInteger)optimalReadLengthWithDefault:(NSUInteger)defaultValue shouldPreBuffer:(BOOL *)shouldPreBufferPtr;
  394. - (NSUInteger)readLengthForNonTermWithHint:(NSUInteger)bytesAvailable;
  395. - (NSUInteger)readLengthForTermWithHint:(NSUInteger)bytesAvailable shouldPreBuffer:(BOOL *)shouldPreBufferPtr;
  396. - (NSUInteger)readLengthForTermWithPreBuffer:(GCDAsyncSocketPreBuffer *)preBuffer found:(BOOL *)foundPtr;
  397. - (NSInteger)searchForTermAfterPreBuffering:(ssize_t)numBytes;
  398. @end
  399. @implementation GCDAsyncReadPacket
  400. - (id)initWithData:(NSMutableData *)d
  401. startOffset:(NSUInteger)s
  402. maxLength:(NSUInteger)m
  403. timeout:(NSTimeInterval)t
  404. readLength:(NSUInteger)l
  405. terminator:(NSData *)e
  406. tag:(long)i
  407. {
  408. if((self = [super init]))
  409. {
  410. bytesDone = 0;
  411. maxLength = m;
  412. timeout = t;
  413. readLength = l;
  414. term = [e copy];
  415. tag = i;
  416. if (d)
  417. {
  418. buffer = d;
  419. startOffset = s;
  420. bufferOwner = NO;
  421. originalBufferLength = [d length];
  422. }
  423. else
  424. {
  425. if (readLength > 0)
  426. buffer = [[NSMutableData alloc] initWithLength:readLength];
  427. else
  428. buffer = [[NSMutableData alloc] initWithLength:0];
  429. startOffset = 0;
  430. bufferOwner = YES;
  431. originalBufferLength = 0;
  432. }
  433. }
  434. return self;
  435. }
  436. /**
  437. * Increases the length of the buffer (if needed) to ensure a read of the given size will fit.
  438. **/
  439. - (void)ensureCapacityForAdditionalDataOfLength:(NSUInteger)bytesToRead
  440. {
  441. NSUInteger buffSize = [buffer length];
  442. NSUInteger buffUsed = startOffset + bytesDone;
  443. NSUInteger buffSpace = buffSize - buffUsed;
  444. if (bytesToRead > buffSpace)
  445. {
  446. NSUInteger buffInc = bytesToRead - buffSpace;
  447. [buffer increaseLengthBy:buffInc];
  448. }
  449. }
  450. /**
  451. * This method is used when we do NOT know how much data is available to be read from the socket.
  452. * This method returns the default value unless it exceeds the specified readLength or maxLength.
  453. *
  454. * Furthermore, the shouldPreBuffer decision is based upon the packet type,
  455. * and whether the returned value would fit in the current buffer without requiring a resize of the buffer.
  456. **/
  457. - (NSUInteger)optimalReadLengthWithDefault:(NSUInteger)defaultValue shouldPreBuffer:(BOOL *)shouldPreBufferPtr
  458. {
  459. NSUInteger result;
  460. if (readLength > 0)
  461. {
  462. // Read a specific length of data
  463. result = MIN(defaultValue, (readLength - bytesDone));
  464. // There is no need to prebuffer since we know exactly how much data we need to read.
  465. // Even if the buffer isn't currently big enough to fit this amount of data,
  466. // it would have to be resized eventually anyway.
  467. if (shouldPreBufferPtr)
  468. *shouldPreBufferPtr = NO;
  469. }
  470. else
  471. {
  472. // Either reading until we find a specified terminator,
  473. // or we're simply reading all available data.
  474. //
  475. // In other words, one of:
  476. //
  477. // - readDataToData packet
  478. // - readDataWithTimeout packet
  479. if (maxLength > 0)
  480. result = MIN(defaultValue, (maxLength - bytesDone));
  481. else
  482. result = defaultValue;
  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. if (shouldPreBufferPtr)
  490. {
  491. NSUInteger buffSize = [buffer length];
  492. NSUInteger buffUsed = startOffset + bytesDone;
  493. NSUInteger buffSpace = buffSize - buffUsed;
  494. if (buffSpace >= result)
  495. *shouldPreBufferPtr = NO;
  496. else
  497. *shouldPreBufferPtr = YES;
  498. }
  499. }
  500. return result;
  501. }
  502. /**
  503. * For read packets without a set terminator, returns the amount of data
  504. * that can be read without exceeding the readLength or maxLength.
  505. *
  506. * The given parameter indicates the number of bytes estimated to be available on the socket,
  507. * which is taken into consideration during the calculation.
  508. *
  509. * The given hint MUST be greater than zero.
  510. **/
  511. - (NSUInteger)readLengthForNonTermWithHint:(NSUInteger)bytesAvailable
  512. {
  513. NSAssert(term == nil, @"This method does not apply to term reads");
  514. NSAssert(bytesAvailable > 0, @"Invalid parameter: bytesAvailable");
  515. if (readLength > 0)
  516. {
  517. // Read a specific length of data
  518. return MIN(bytesAvailable, (readLength - bytesDone));
  519. // No need to avoid resizing the buffer.
  520. // If the user provided their own buffer,
  521. // and told us to read a certain length of data that exceeds the size of the buffer,
  522. // then it is clear that our code will resize the buffer during the read operation.
  523. //
  524. // This method does not actually do any resizing.
  525. // The resizing will happen elsewhere if needed.
  526. }
  527. else
  528. {
  529. // Read all available data
  530. NSUInteger result = bytesAvailable;
  531. if (maxLength > 0)
  532. {
  533. result = MIN(result, (maxLength - bytesDone));
  534. }
  535. // No need to avoid resizing the buffer.
  536. // If the user provided their own buffer,
  537. // and told us to read all available data without giving us a maxLength,
  538. // then it is clear that our code might resize the buffer during the read operation.
  539. //
  540. // This method does not actually do any resizing.
  541. // The resizing will happen elsewhere if needed.
  542. return result;
  543. }
  544. }
  545. /**
  546. * For read packets with a set terminator, returns the amount of data
  547. * that can be read without exceeding the maxLength.
  548. *
  549. * The given parameter indicates the number of bytes estimated to be available on the socket,
  550. * which is taken into consideration during the calculation.
  551. *
  552. * To optimize memory allocations, mem copies, and mem moves
  553. * the shouldPreBuffer boolean value will indicate if the data should be read into a prebuffer first,
  554. * or if the data can be read directly into the read packet's buffer.
  555. **/
  556. - (NSUInteger)readLengthForTermWithHint:(NSUInteger)bytesAvailable shouldPreBuffer:(BOOL *)shouldPreBufferPtr
  557. {
  558. NSAssert(term != nil, @"This method does not apply to non-term reads");
  559. NSAssert(bytesAvailable > 0, @"Invalid parameter: bytesAvailable");
  560. NSUInteger result = bytesAvailable;
  561. if (maxLength > 0)
  562. {
  563. result = MIN(result, (maxLength - bytesDone));
  564. }
  565. // Should the data be read into the read packet's buffer, or into a pre-buffer first?
  566. //
  567. // One would imagine the preferred option is the faster one.
  568. // So which one is faster?
  569. //
  570. // Reading directly into the packet's buffer requires:
  571. // 1. Possibly resizing packet buffer (malloc/realloc)
  572. // 2. Filling buffer (read)
  573. // 3. Searching for term (memcmp)
  574. // 4. Possibly copying overflow into prebuffer (malloc/realloc, memcpy)
  575. //
  576. // Reading into prebuffer first:
  577. // 1. Possibly resizing prebuffer (malloc/realloc)
  578. // 2. Filling buffer (read)
  579. // 3. Searching for term (memcmp)
  580. // 4. Copying underflow into packet buffer (malloc/realloc, memcpy)
  581. // 5. Removing underflow from prebuffer (memmove)
  582. //
  583. // Comparing the performance of the two we can see that reading
  584. // data into the prebuffer first is slower due to the extra memove.
  585. //
  586. // However:
  587. // The implementation of NSMutableData is open source via core foundation's CFMutableData.
  588. // Decreasing the length of a mutable data object doesn't cause a realloc.
  589. // In other words, the capacity of a mutable data object can grow, but doesn't shrink.
  590. //
  591. // This means the prebuffer will rarely need a realloc.
  592. // The packet buffer, on the other hand, may often need a realloc.
  593. // This is especially true if we are the buffer owner.
  594. // Furthermore, if we are constantly realloc'ing the packet buffer,
  595. // and then moving the overflow into the prebuffer,
  596. // then we're consistently over-allocating memory for each term read.
  597. // And now we get into a bit of a tradeoff between speed and memory utilization.
  598. //
  599. // The end result is that the two perform very similarly.
  600. // And we can answer the original question very simply by another means.
  601. //
  602. // If we can read all the data directly into the packet's buffer without resizing it first,
  603. // then we do so. Otherwise we use the prebuffer.
  604. if (shouldPreBufferPtr)
  605. {
  606. NSUInteger buffSize = [buffer length];
  607. NSUInteger buffUsed = startOffset + bytesDone;
  608. if ((buffSize - buffUsed) >= result)
  609. *shouldPreBufferPtr = NO;
  610. else
  611. *shouldPreBufferPtr = YES;
  612. }
  613. return result;
  614. }
  615. /**
  616. * For read packets with a set terminator,
  617. * returns the amount of data that can be read from the given preBuffer,
  618. * without going over a terminator or the maxLength.
  619. *
  620. * It is assumed the terminator has not already been read.
  621. **/
  622. - (NSUInteger)readLengthForTermWithPreBuffer:(GCDAsyncSocketPreBuffer *)preBuffer found:(BOOL *)foundPtr
  623. {
  624. NSAssert(term != nil, @"This method does not apply to non-term reads");
  625. NSAssert([preBuffer availableBytes] > 0, @"Invoked with empty pre buffer!");
  626. // We know that the terminator, as a whole, doesn't exist in our own buffer.
  627. // But it is possible that a _portion_ of it exists in our buffer.
  628. // So we're going to look for the terminator starting with a portion of our own buffer.
  629. //
  630. // Example:
  631. //
  632. // term length = 3 bytes
  633. // bytesDone = 5 bytes
  634. // preBuffer length = 5 bytes
  635. //
  636. // If we append the preBuffer to our buffer,
  637. // it would look like this:
  638. //
  639. // ---------------------
  640. // |B|B|B|B|B|P|P|P|P|P|
  641. // ---------------------
  642. //
  643. // So we start our search here:
  644. //
  645. // ---------------------
  646. // |B|B|B|B|B|P|P|P|P|P|
  647. // -------^-^-^---------
  648. //
  649. // And move forwards...
  650. //
  651. // ---------------------
  652. // |B|B|B|B|B|P|P|P|P|P|
  653. // ---------^-^-^-------
  654. //
  655. // Until we find the terminator or reach the end.
  656. //
  657. // ---------------------
  658. // |B|B|B|B|B|P|P|P|P|P|
  659. // ---------------^-^-^-
  660. BOOL found = NO;
  661. NSUInteger termLength = [term length];
  662. NSUInteger preBufferLength = [preBuffer availableBytes];
  663. if ((bytesDone + preBufferLength) < termLength)
  664. {
  665. // Not enough data for a full term sequence yet
  666. return preBufferLength;
  667. }
  668. NSUInteger maxPreBufferLength;
  669. if (maxLength > 0) {
  670. maxPreBufferLength = MIN(preBufferLength, (maxLength - bytesDone));
  671. // Note: maxLength >= termLength
  672. }
  673. else {
  674. maxPreBufferLength = preBufferLength;
  675. }
  676. uint8_t seq[termLength];
  677. const void *termBuf = [term bytes];
  678. NSUInteger bufLen = MIN(bytesDone, (termLength - 1));
  679. uint8_t *buf = (uint8_t *)[buffer mutableBytes] + startOffset + bytesDone - bufLen;
  680. NSUInteger preLen = termLength - bufLen;
  681. const uint8_t *pre = [preBuffer readBuffer];
  682. NSUInteger loopCount = bufLen + maxPreBufferLength - termLength + 1; // Plus one. See example above.
  683. NSUInteger result = maxPreBufferLength;
  684. NSUInteger i;
  685. for (i = 0; i < loopCount; i++)
  686. {
  687. if (bufLen > 0)
  688. {
  689. // Combining bytes from buffer and preBuffer
  690. memcpy(seq, buf, bufLen);
  691. memcpy(seq + bufLen, pre, preLen);
  692. if (memcmp(seq, termBuf, termLength) == 0)
  693. {
  694. result = preLen;
  695. found = YES;
  696. break;
  697. }
  698. buf++;
  699. bufLen--;
  700. preLen++;
  701. }
  702. else
  703. {
  704. // Comparing directly from preBuffer
  705. if (memcmp(pre, termBuf, termLength) == 0)
  706. {
  707. NSUInteger preOffset = pre - [preBuffer readBuffer]; // pointer arithmetic
  708. result = preOffset + termLength;
  709. found = YES;
  710. break;
  711. }
  712. pre++;
  713. }
  714. }
  715. // There is no need to avoid resizing the buffer in this particular situation.
  716. if (foundPtr) *foundPtr = found;
  717. return result;
  718. }
  719. /**
  720. * For read packets with a set terminator, scans the packet buffer for the term.
  721. * It is assumed the terminator had not been fully read prior to the new bytes.
  722. *
  723. * If the term is found, the number of excess bytes after the term are returned.
  724. * If the term is not found, this method will return -1.
  725. *
  726. * Note: A return value of zero means the term was found at the very end.
  727. *
  728. * Prerequisites:
  729. * The given number of bytes have been added to the end of our buffer.
  730. * Our bytesDone variable has NOT been changed due to the prebuffered bytes.
  731. **/
  732. - (NSInteger)searchForTermAfterPreBuffering:(ssize_t)numBytes
  733. {
  734. NSAssert(term != nil, @"This method does not apply to non-term reads");
  735. // The implementation of this method is very similar to the above method.
  736. // See the above method for a discussion of the algorithm used here.
  737. uint8_t *buff = [buffer mutableBytes];
  738. NSUInteger buffLength = bytesDone + numBytes;
  739. const void *termBuff = [term bytes];
  740. NSUInteger termLength = [term length];
  741. // Note: We are dealing with unsigned integers,
  742. // so make sure the math doesn't go below zero.
  743. NSUInteger i = ((buffLength - numBytes) >= termLength) ? (buffLength - numBytes - termLength + 1) : 0;
  744. while (i + termLength <= buffLength)
  745. {
  746. uint8_t *subBuffer = buff + startOffset + i;
  747. if (memcmp(subBuffer, termBuff, termLength) == 0)
  748. {
  749. return buffLength - (i + termLength);
  750. }
  751. i++;
  752. }
  753. return -1;
  754. }
  755. @end
  756. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  757. #pragma mark -
  758. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  759. /**
  760. * The GCDAsyncWritePacket encompasses the instructions for any given write.
  761. **/
  762. @interface GCDAsyncWritePacket : NSObject
  763. {
  764. @public
  765. NSData *buffer;
  766. NSUInteger bytesDone;
  767. long tag;
  768. NSTimeInterval timeout;
  769. }
  770. - (id)initWithData:(NSData *)d timeout:(NSTimeInterval)t tag:(long)i;
  771. @end
  772. @implementation GCDAsyncWritePacket
  773. - (id)initWithData:(NSData *)d timeout:(NSTimeInterval)t tag:(long)i
  774. {
  775. if((self = [super init]))
  776. {
  777. buffer = d; // Retain not copy. For performance as documented in header file.
  778. bytesDone = 0;
  779. timeout = t;
  780. tag = i;
  781. }
  782. return self;
  783. }
  784. @end
  785. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  786. #pragma mark -
  787. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  788. /**
  789. * The GCDAsyncSpecialPacket encompasses special instructions for interruptions in the read/write queues.
  790. * This class my be altered to support more than just TLS in the future.
  791. **/
  792. @interface GCDAsyncSpecialPacket : NSObject
  793. {
  794. @public
  795. NSDictionary *tlsSettings;
  796. }
  797. - (id)initWithTLSSettings:(NSDictionary *)settings;
  798. @end
  799. @implementation GCDAsyncSpecialPacket
  800. - (id)initWithTLSSettings:(NSDictionary *)settings
  801. {
  802. if((self = [super init]))
  803. {
  804. tlsSettings = [settings copy];
  805. }
  806. return self;
  807. }
  808. @end
  809. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  810. #pragma mark -
  811. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  812. @implementation GCDAsyncSocket
  813. - (id)init
  814. {
  815. return [self initWithDelegate:nil delegateQueue:NULL socketQueue:NULL];
  816. }
  817. - (id)initWithSocketQueue:(dispatch_queue_t)sq
  818. {
  819. return [self initWithDelegate:nil delegateQueue:NULL socketQueue:sq];
  820. }
  821. - (id)initWithDelegate:(id)aDelegate delegateQueue:(dispatch_queue_t)dq
  822. {
  823. return [self initWithDelegate:aDelegate delegateQueue:dq socketQueue:NULL];
  824. }
  825. - (id)initWithDelegate:(id)aDelegate delegateQueue:(dispatch_queue_t)dq socketQueue:(dispatch_queue_t)sq
  826. {
  827. if((self = [super init]))
  828. {
  829. delegate = aDelegate;
  830. delegateQueue = dq;
  831. #if NEEDS_DISPATCH_RETAIN_RELEASE
  832. if (dq) dispatch_retain(dq);
  833. #endif
  834. socket4FD = SOCKET_NULL;
  835. socket6FD = SOCKET_NULL;
  836. socketUN = SOCKET_NULL;
  837. socketUrl = nil;
  838. connectIndex = 0;
  839. if (sq)
  840. {
  841. NSAssert(sq != dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0),
  842. @"The given socketQueue parameter must not be a concurrent queue.");
  843. NSAssert(sq != dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0),
  844. @"The given socketQueue parameter must not be a concurrent queue.");
  845. NSAssert(sq != dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),
  846. @"The given socketQueue parameter must not be a concurrent queue.");
  847. socketQueue = sq;
  848. #if NEEDS_DISPATCH_RETAIN_RELEASE
  849. dispatch_retain(sq);
  850. #endif
  851. }
  852. else
  853. {
  854. socketQueue = dispatch_queue_create([GCDAsyncSocketQueueName UTF8String], NULL);
  855. }
  856. readQueue = [[NSMutableArray alloc] initWithCapacity:5];
  857. currentRead = nil;
  858. writeQueue = [[NSMutableArray alloc] initWithCapacity:5];
  859. currentWrite = nil;
  860. preBuffer = [[GCDAsyncSocketPreBuffer alloc] initWithCapacity:(1024 * 4)];
  861. }
  862. return self;
  863. }
  864. - (void)dealloc
  865. {
  866. LogInfo(@"%@ - %@ (start)", THIS_METHOD, self);
  867. if (dispatch_get_current_queue() == socketQueue)
  868. {
  869. [self closeWithError:nil];
  870. }
  871. else
  872. {
  873. dispatch_sync(socketQueue, ^{
  874. [self closeWithError:nil];
  875. });
  876. }
  877. delegate = nil;
  878. #if NEEDS_DISPATCH_RETAIN_RELEASE
  879. if (delegateQueue) dispatch_release(delegateQueue);
  880. #endif
  881. delegateQueue = NULL;
  882. #if NEEDS_DISPATCH_RETAIN_RELEASE
  883. if (socketQueue) dispatch_release(socketQueue);
  884. #endif
  885. socketQueue = NULL;
  886. LogInfo(@"%@ - %@ (finish)", THIS_METHOD, self);
  887. }
  888. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  889. #pragma mark Configuration
  890. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  891. - (id)delegate
  892. {
  893. if (dispatch_get_current_queue() == socketQueue)
  894. {
  895. return delegate;
  896. }
  897. else
  898. {
  899. __block id result;
  900. dispatch_sync(socketQueue, ^{
  901. result = delegate;
  902. });
  903. return result;
  904. }
  905. }
  906. - (void)setDelegate:(id)newDelegate synchronously:(BOOL)synchronously
  907. {
  908. dispatch_block_t block = ^{
  909. delegate = newDelegate;
  910. };
  911. if (dispatch_get_current_queue() == socketQueue) {
  912. block();
  913. }
  914. else {
  915. if (synchronously)
  916. dispatch_sync(socketQueue, block);
  917. else
  918. dispatch_async(socketQueue, block);
  919. }
  920. }
  921. - (void)setDelegate:(id)newDelegate
  922. {
  923. [self setDelegate:newDelegate synchronously:NO];
  924. }
  925. - (void)synchronouslySetDelegate:(id)newDelegate
  926. {
  927. [self setDelegate:newDelegate synchronously:YES];
  928. }
  929. - (dispatch_queue_t)delegateQueue
  930. {
  931. if (dispatch_get_current_queue() == socketQueue)
  932. {
  933. return delegateQueue;
  934. }
  935. else
  936. {
  937. __block dispatch_queue_t result;
  938. dispatch_sync(socketQueue, ^{
  939. result = delegateQueue;
  940. });
  941. return result;
  942. }
  943. }
  944. - (void)setDelegateQueue:(dispatch_queue_t)newDelegateQueue synchronously:(BOOL)synchronously
  945. {
  946. dispatch_block_t block = ^{
  947. #if NEEDS_DISPATCH_RETAIN_RELEASE
  948. if (delegateQueue) dispatch_release(delegateQueue);
  949. if (newDelegateQueue) dispatch_retain(newDelegateQueue);
  950. #endif
  951. delegateQueue = newDelegateQueue;
  952. };
  953. if (dispatch_get_current_queue() == socketQueue) {
  954. block();
  955. }
  956. else {
  957. if (synchronously)
  958. dispatch_sync(socketQueue, block);
  959. else
  960. dispatch_async(socketQueue, block);
  961. }
  962. }
  963. - (void)setDelegateQueue:(dispatch_queue_t)newDelegateQueue
  964. {
  965. [self setDelegateQueue:newDelegateQueue synchronously:NO];
  966. }
  967. - (void)synchronouslySetDelegateQueue:(dispatch_queue_t)newDelegateQueue
  968. {
  969. [self setDelegateQueue:newDelegateQueue synchronously:YES];
  970. }
  971. - (void)getDelegate:(id *)delegatePtr delegateQueue:(dispatch_queue_t *)delegateQueuePtr
  972. {
  973. if (dispatch_get_current_queue() == socketQueue)
  974. {
  975. if (delegatePtr) *delegatePtr = delegate;
  976. if (delegateQueuePtr) *delegateQueuePtr = delegateQueue;
  977. }
  978. else
  979. {
  980. __block id dPtr = NULL;
  981. __block dispatch_queue_t dqPtr = NULL;
  982. dispatch_sync(socketQueue, ^{
  983. dPtr = delegate;
  984. dqPtr = delegateQueue;
  985. });
  986. if (delegatePtr) *delegatePtr = dPtr;
  987. if (delegateQueuePtr) *delegateQueuePtr = dqPtr;
  988. }
  989. }
  990. - (void)setDelegate:(id)newDelegate delegateQueue:(dispatch_queue_t)newDelegateQueue synchronously:(BOOL)synchronously
  991. {
  992. dispatch_block_t block = ^{
  993. delegate = newDelegate;
  994. #if NEEDS_DISPATCH_RETAIN_RELEASE
  995. if (delegateQueue) dispatch_release(delegateQueue);
  996. if (newDelegateQueue) dispatch_retain(newDelegateQueue);
  997. #endif
  998. delegateQueue = newDelegateQueue;
  999. };
  1000. if (dispatch_get_current_queue() == socketQueue) {
  1001. block();
  1002. }
  1003. else {
  1004. if (synchronously)
  1005. dispatch_sync(socketQueue, block);
  1006. else
  1007. dispatch_async(socketQueue, block);
  1008. }
  1009. }
  1010. - (void)setDelegate:(id)newDelegate delegateQueue:(dispatch_queue_t)newDelegateQueue
  1011. {
  1012. [self setDelegate:newDelegate delegateQueue:newDelegateQueue synchronously:NO];
  1013. }
  1014. - (void)synchronouslySetDelegate:(id)newDelegate delegateQueue:(dispatch_queue_t)newDelegateQueue
  1015. {
  1016. [self setDelegate:newDelegate delegateQueue:newDelegateQueue synchronously:YES];
  1017. }
  1018. - (BOOL)autoDisconnectOnClosedReadStream
  1019. {
  1020. // Note: YES means kAllowHalfDuplexConnection is OFF
  1021. if (dispatch_get_current_queue() == socketQueue)
  1022. {
  1023. return ((config & kAllowHalfDuplexConnection) == 0);
  1024. }
  1025. else
  1026. {
  1027. __block BOOL result;
  1028. dispatch_sync(socketQueue, ^{
  1029. result = ((config & kAllowHalfDuplexConnection) == 0);
  1030. });
  1031. return result;
  1032. }
  1033. }
  1034. - (void)setAutoDisconnectOnClosedReadStream:(BOOL)flag
  1035. {
  1036. // Note: YES means kAllowHalfDuplexConnection is OFF
  1037. dispatch_block_t block = ^{
  1038. if (flag)
  1039. config &= ~kAllowHalfDuplexConnection;
  1040. else
  1041. config |= kAllowHalfDuplexConnection;
  1042. };
  1043. if (dispatch_get_current_queue() == socketQueue)
  1044. block();
  1045. else
  1046. dispatch_async(socketQueue, block);
  1047. }
  1048. - (BOOL)isIPv4Enabled
  1049. {
  1050. // Note: YES means kIPv4Disabled is OFF
  1051. if (dispatch_get_current_queue() == socketQueue)
  1052. {
  1053. return ((config & kIPv4Disabled) == 0);
  1054. }
  1055. else
  1056. {
  1057. __block BOOL result;
  1058. dispatch_sync(socketQueue, ^{
  1059. result = ((config & kIPv4Disabled) == 0);
  1060. });
  1061. return result;
  1062. }
  1063. }
  1064. - (void)setIPv4Enabled:(BOOL)flag
  1065. {
  1066. // Note: YES means kIPv4Disabled is OFF
  1067. dispatch_block_t block = ^{
  1068. if (flag)
  1069. config &= ~kIPv4Disabled;
  1070. else
  1071. config |= kIPv4Disabled;
  1072. };
  1073. if (dispatch_get_current_queue() == socketQueue)
  1074. block();
  1075. else
  1076. dispatch_async(socketQueue, block);
  1077. }
  1078. - (BOOL)isIPv6Enabled
  1079. {
  1080. // Note: YES means kIPv6Disabled is OFF
  1081. if (dispatch_get_current_queue() == socketQueue)
  1082. {
  1083. return ((config & kIPv6Disabled) == 0);
  1084. }
  1085. else
  1086. {
  1087. __block BOOL result;
  1088. dispatch_sync(socketQueue, ^{
  1089. result = ((config & kIPv6Disabled) == 0);
  1090. });
  1091. return result;
  1092. }
  1093. }
  1094. - (void)setIPv6Enabled:(BOOL)flag
  1095. {
  1096. // Note: YES means kIPv6Disabled is OFF
  1097. dispatch_block_t block = ^{
  1098. if (flag)
  1099. config &= ~kIPv6Disabled;
  1100. else
  1101. config |= kIPv6Disabled;
  1102. };
  1103. if (dispatch_get_current_queue() == socketQueue)
  1104. block();
  1105. else
  1106. dispatch_async(socketQueue, block);
  1107. }
  1108. - (BOOL)isIPv4PreferredOverIPv6
  1109. {
  1110. // Note: YES means kPreferIPv6 is OFF
  1111. if (dispatch_get_current_queue() == socketQueue)
  1112. {
  1113. return ((config & kPreferIPv6) == 0);
  1114. }
  1115. else
  1116. {
  1117. __block BOOL result;
  1118. dispatch_sync(socketQueue, ^{
  1119. result = ((config & kPreferIPv6) == 0);
  1120. });
  1121. return result;
  1122. }
  1123. }
  1124. - (void)setPreferIPv4OverIPv6:(BOOL)flag
  1125. {
  1126. // Note: YES means kPreferIPv6 is OFF
  1127. dispatch_block_t block = ^{
  1128. if (flag)
  1129. config &= ~kPreferIPv6;
  1130. else
  1131. config |= kPreferIPv6;
  1132. };
  1133. if (dispatch_get_current_queue() == socketQueue)
  1134. block();
  1135. else
  1136. dispatch_async(socketQueue, block);
  1137. }
  1138. - (id)userData
  1139. {
  1140. __block id result = nil;
  1141. dispatch_block_t block = ^{
  1142. result = userData;
  1143. };
  1144. if (dispatch_get_current_queue() == socketQueue)
  1145. block();
  1146. else
  1147. dispatch_sync(socketQueue, block);
  1148. return result;
  1149. }
  1150. - (void)setUserData:(id)arbitraryUserData
  1151. {
  1152. dispatch_block_t block = ^{
  1153. if (userData != arbitraryUserData)
  1154. {
  1155. userData = arbitraryUserData;
  1156. }
  1157. };
  1158. if (dispatch_get_current_queue() == socketQueue)
  1159. block();
  1160. else
  1161. dispatch_async(socketQueue, block);
  1162. }
  1163. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1164. #pragma mark Accepting
  1165. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1166. - (BOOL)acceptOnPort:(uint16_t)port error:(NSError **)errPtr
  1167. {
  1168. return [self acceptOnInterface:nil port:port error:errPtr];
  1169. }
  1170. - (BOOL)acceptOnInterface:(NSString *)inInterface port:(uint16_t)port error:(NSError **)errPtr
  1171. {
  1172. LogTrace();
  1173. // Just in-case interface parameter is immutable.
  1174. NSString *interface = [inInterface copy];
  1175. __block BOOL result = NO;
  1176. __block NSError *err = nil;
  1177. // CreateSocket Block
  1178. // This block will be invoked within the dispatch block below.
  1179. int(^createSocket)(int, NSData*) = ^int (int domain, NSData *interfaceAddr) {
  1180. int socketFD = socket(domain, SOCK_STREAM, 0);
  1181. if (socketFD == SOCKET_NULL)
  1182. {
  1183. NSString *reason = @"Error in socket() function";
  1184. err = [self errnoErrorWithReason:reason];
  1185. return SOCKET_NULL;
  1186. }
  1187. int status;
  1188. // Set socket options
  1189. status = fcntl(socketFD, F_SETFL, O_NONBLOCK);
  1190. if (status == -1)
  1191. {
  1192. NSString *reason = @"Error enabling non-blocking IO on socket (fcntl)";
  1193. err = [self errnoErrorWithReason:reason];
  1194. LogVerbose(@"close(socketFD)");
  1195. close(socketFD);
  1196. return SOCKET_NULL;
  1197. }
  1198. int reuseOn = 1;
  1199. status = setsockopt(socketFD, SOL_SOCKET, SO_REUSEADDR, &reuseOn, sizeof(reuseOn));
  1200. if (status == -1)
  1201. {
  1202. NSString *reason = @"Error enabling address reuse (setsockopt)";
  1203. err = [self errnoErrorWithReason:reason];
  1204. LogVerbose(@"close(socketFD)");
  1205. close(socketFD);
  1206. return SOCKET_NULL;
  1207. }
  1208. // Bind socket
  1209. const struct sockaddr *addr = (const struct sockaddr *)[interfaceAddr bytes];
  1210. status = bind(socketFD, addr, addr->sa_len);
  1211. if (status == -1)
  1212. {
  1213. NSString *reason = @"Error in bind() function";
  1214. err = [self errnoErrorWithReason:reason];
  1215. LogVerbose(@"close(socketFD)");
  1216. close(socketFD);
  1217. return SOCKET_NULL;
  1218. }
  1219. // Listen
  1220. status = listen(socketFD, 1024);
  1221. if (status == -1)
  1222. {
  1223. NSString *reason = @"Error in listen() function";
  1224. err = [self errnoErrorWithReason:reason];
  1225. LogVerbose(@"close(socketFD)");
  1226. close(socketFD);
  1227. return SOCKET_NULL;
  1228. }
  1229. return socketFD;
  1230. };
  1231. // Create dispatch block and run on socketQueue
  1232. dispatch_block_t block = ^{ @autoreleasepool {
  1233. if (delegate == nil) // Must have delegate set
  1234. {
  1235. NSString *msg = @"Attempting to accept without a delegate. Set a delegate first.";
  1236. err = [self badConfigError:msg];
  1237. return_from_block;
  1238. }
  1239. if (delegateQueue == NULL) // Must have delegate queue set
  1240. {
  1241. NSString *msg = @"Attempting to accept without a delegate queue. Set a delegate queue first.";
  1242. err = [self badConfigError:msg];
  1243. return_from_block;
  1244. }
  1245. BOOL isIPv4Disabled = (config & kIPv4Disabled) ? YES : NO;
  1246. BOOL isIPv6Disabled = (config & kIPv6Disabled) ? YES : NO;
  1247. if (isIPv4Disabled && isIPv6Disabled) // Must have IPv4 or IPv6 enabled
  1248. {
  1249. NSString *msg = @"Both IPv4 and IPv6 have been disabled. Must enable at least one protocol first.";
  1250. err = [self badConfigError:msg];
  1251. return_from_block;
  1252. }
  1253. if (![self isDisconnected]) // Must be disconnected
  1254. {
  1255. NSString *msg = @"Attempting to accept while connected or accepting connections. Disconnect first.";
  1256. err = [self badConfigError:msg];
  1257. return_from_block;
  1258. }
  1259. // Clear queues (spurious read/write requests post disconnect)
  1260. [readQueue removeAllObjects];
  1261. [writeQueue removeAllObjects];
  1262. // Resolve interface from description
  1263. NSMutableData *interface4 = nil;
  1264. NSMutableData *interface6 = nil;
  1265. [self getInterfaceAddress4:&interface4 address6:&interface6 fromDescription:interface port:port];
  1266. if ((interface4 == nil) && (interface6 == nil))
  1267. {
  1268. NSString *msg = @"Unknown interface. Specify valid interface by name (e.g. \"en1\") or IP address.";
  1269. err = [self badParamError:msg];
  1270. return_from_block;
  1271. }
  1272. if (isIPv4Disabled && (interface6 == nil))
  1273. {
  1274. NSString *msg = @"IPv4 has been disabled and specified interface doesn't support IPv6.";
  1275. err = [self badParamError:msg];
  1276. return_from_block;
  1277. }
  1278. if (isIPv6Disabled && (interface4 == nil))
  1279. {
  1280. NSString *msg = @"IPv6 has been disabled and specified interface doesn't support IPv4.";
  1281. err = [self badParamError:msg];
  1282. return_from_block;
  1283. }
  1284. BOOL enableIPv4 = !isIPv4Disabled && (interface4 != nil);
  1285. BOOL enableIPv6 = !isIPv6Disabled && (interface6 != nil);
  1286. // Create sockets, configure, bind, and listen
  1287. if (enableIPv4)
  1288. {
  1289. LogVerbose(@"Creating IPv4 socket");
  1290. socket4FD = createSocket(AF_INET, interface4);
  1291. if (socket4FD == SOCKET_NULL)
  1292. {
  1293. return_from_block;
  1294. }
  1295. }
  1296. if (enableIPv6)
  1297. {
  1298. LogVerbose(@"Creating IPv6 socket");
  1299. if (enableIPv4 && (port == 0))
  1300. {
  1301. // No specific port was specified, so we allowed the OS to pick an available port for us.
  1302. // Now we need to make sure the IPv6 socket listens on the same port as the IPv4 socket.
  1303. struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)[interface6 mutableBytes];
  1304. addr6->sin6_port = htons([self localPort4]);
  1305. }
  1306. socket6FD = createSocket(AF_INET6, interface6);
  1307. if (socket6FD == SOCKET_NULL)
  1308. {
  1309. if (socket4FD != SOCKET_NULL)
  1310. {
  1311. LogVerbose(@"close(socket4FD)");
  1312. close(socket4FD);
  1313. }
  1314. return_from_block;
  1315. }
  1316. }
  1317. // Create accept sources
  1318. if (enableIPv4)
  1319. {
  1320. accept4Source = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, socket4FD, 0, socketQueue);
  1321. int socketFD = socket4FD;
  1322. dispatch_source_t acceptSource = accept4Source;
  1323. dispatch_source_set_event_handler(accept4Source, ^{ @autoreleasepool {
  1324. LogVerbose(@"event4Block");
  1325. unsigned long i = 0;
  1326. unsigned long numPendingConnections = dispatch_source_get_data(acceptSource);
  1327. LogVerbose(@"numPendingConnections: %lu", numPendingConnections);
  1328. while ([self doAccept:socketFD] && (++i < numPendingConnections));
  1329. }});
  1330. dispatch_source_set_cancel_handler(accept4Source, ^{
  1331. #if NEEDS_DISPATCH_RETAIN_RELEASE
  1332. LogVerbose(@"dispatch_release(accept4Source)");
  1333. dispatch_release(acceptSource);
  1334. #endif
  1335. LogVerbose(@"close(socket4FD)");
  1336. close(socketFD);
  1337. });
  1338. LogVerbose(@"dispatch_resume(accept4Source)");
  1339. dispatch_resume(accept4Source);
  1340. }
  1341. if (enableIPv6)
  1342. {
  1343. accept6Source = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, socket6FD, 0, socketQueue);
  1344. int socketFD = socket6FD;
  1345. dispatch_source_t acceptSource = accept6Source;
  1346. dispatch_source_set_event_handler(accept6Source, ^{ @autoreleasepool {
  1347. LogVerbose(@"event6Block");
  1348. unsigned long i = 0;
  1349. unsigned long numPendingConnections = dispatch_source_get_data(acceptSource);
  1350. LogVerbose(@"numPendingConnections: %lu", numPendingConnections);
  1351. while ([self doAccept:socketFD] && (++i < numPendingConnections));
  1352. }});
  1353. dispatch_source_set_cancel_handler(accept6Source, ^{
  1354. #if NEEDS_DISPATCH_RETAIN_RELEASE
  1355. LogVerbose(@"dispatch_release(accept6Source)");
  1356. dispatch_release(acceptSource);
  1357. #endif
  1358. LogVerbose(@"close(socket6FD)");
  1359. close(socketFD);
  1360. });
  1361. LogVerbose(@"dispatch_resume(accept6Source)");
  1362. dispatch_resume(accept6Source);
  1363. }
  1364. flags |= kSocketStarted;
  1365. result = YES;
  1366. }};
  1367. if (dispatch_get_current_queue() == socketQueue)
  1368. block();
  1369. else
  1370. dispatch_sync(socketQueue, block);
  1371. if (result == NO)
  1372. {
  1373. LogInfo(@"Error in accept: %@", err);
  1374. if (errPtr)
  1375. *errPtr = err;
  1376. }
  1377. return result;
  1378. }
  1379. - (BOOL)acceptOnUrl:(NSURL *)url error:(NSError **)errPtr;
  1380. {
  1381. LogTrace();
  1382. __block BOOL result = NO;
  1383. __block NSError *err = nil;
  1384. // CreateSocket Block
  1385. // This block will be invoked within the dispatch block below.
  1386. int(^createSocket)(int, NSData*) = ^int (int domain, NSData *interfaceAddr) {
  1387. int socketFD = socket(domain, SOCK_STREAM, 0);
  1388. if (socketFD == SOCKET_NULL)
  1389. {
  1390. NSString *reason = @"Error in socket() function";
  1391. err = [self errnoErrorWithReason:reason];
  1392. return SOCKET_NULL;
  1393. }
  1394. int status;
  1395. // Set socket options
  1396. status = fcntl(socketFD, F_SETFL, O_NONBLOCK);
  1397. if (status == -1)
  1398. {
  1399. NSString *reason = @"Error enabling non-blocking IO on socket (fcntl)";
  1400. err = [self errnoErrorWithReason:reason];
  1401. LogVerbose(@"close(socketFD)");
  1402. close(socketFD);
  1403. return SOCKET_NULL;
  1404. }
  1405. int reuseOn = 1;
  1406. status = setsockopt(socketFD, SOL_SOCKET, SO_REUSEADDR, &reuseOn, sizeof(reuseOn));
  1407. if (status == -1)
  1408. {
  1409. NSString *reason = @"Error enabling address reuse (setsockopt)";
  1410. err = [self errnoErrorWithReason:reason];
  1411. LogVerbose(@"close(socketFD)");
  1412. close(socketFD);
  1413. return SOCKET_NULL;
  1414. }
  1415. // Bind socket
  1416. status = bind(socketFD, (const struct sockaddr *)[interfaceAddr bytes], (socklen_t)[interfaceAddr length]);
  1417. if (status == -1)
  1418. {
  1419. NSString *reason = @"Error in bind() function";
  1420. err = [self errnoErrorWithReason:reason];
  1421. LogVerbose(@"close(socketFD)");
  1422. close(socketFD);
  1423. return SOCKET_NULL;
  1424. }
  1425. // Listen
  1426. status = listen(socketFD, 1024);
  1427. if (status == -1)
  1428. {
  1429. NSString *reason = @"Error in listen() function";
  1430. err = [self errnoErrorWithReason:reason];
  1431. LogVerbose(@"close(socketFD)");
  1432. close(socketFD);
  1433. return SOCKET_NULL;
  1434. }
  1435. return socketFD;
  1436. };
  1437. // Create dispatch block and run on socketQueue
  1438. dispatch_block_t block = ^{ @autoreleasepool {
  1439. if (delegate == nil) // Must have delegate set
  1440. {
  1441. NSString *msg = @"Attempting to accept without a delegate. Set a delegate first.";
  1442. err = [self badConfigError:msg];
  1443. return_from_block;
  1444. }
  1445. if (delegateQueue == NULL) // Must have delegate queue set
  1446. {
  1447. NSString *msg = @"Attempting to accept without a delegate queue. Set a delegate queue first.";
  1448. err = [self badConfigError:msg];
  1449. return_from_block;
  1450. }
  1451. if (![self isDisconnected]) // Must be disconnected
  1452. {
  1453. NSString *msg = @"Attempting to accept while connected or accepting connections. Disconnect first.";
  1454. err = [self badConfigError:msg];
  1455. return_from_block;
  1456. }
  1457. // Clear queues (spurious read/write requests post disconnect)
  1458. [readQueue removeAllObjects];
  1459. [writeQueue removeAllObjects];
  1460. // Remove a previous socket
  1461. NSError *error = nil;
  1462. NSFileManager *fileManager = [NSFileManager defaultManager];
  1463. if ([fileManager fileExistsAtPath:url.path]) {
  1464. if (![[NSFileManager defaultManager] removeItemAtURL:url error:&error]) {
  1465. NSString *msg = @"Could not remove previous unix domain socket at given url.";
  1466. err

Large files files are truncated, but you can click here to view the full file