PageRenderTime 37ms CodeModel.GetById 1ms RepoModel.GetById 0ms app.codeStats 1ms

/mio/GCDAsyncUdpSocket.m

https://gitlab.com/base.io/mio
Objective C | 1936 lines | 1357 code | 450 blank | 129 comment | 261 complexity | 30039fa0fafa5f9bc4ecafda7d81e233 MD5 | raw file
  1. //
  2. // GCDAsyncUdpSocket
  3. //
  4. // This class is in the public domain.
  5. // Originally created by Robbie Hanson of Deusty LLC.
  6. // Updated and maintained by Deusty LLC and the Apple development community.
  7. //
  8. // https://github.com/robbiehanson/CocoaAsyncSocket
  9. //
  10. #if ! __has_feature(objc_arc)
  11. #warning This file must be compiled with ARC. Use -fobjc-arc flag (or convert project to ARC).
  12. // For more information see: https://github.com/robbiehanson/CocoaAsyncSocket/wiki/ARC
  13. #endif
  14. /**
  15. * Does ARC support support GCD objects?
  16. * It does if the minimum deployment target is iOS 6+ or Mac OS X 8+
  17. **/
  18. #if TARGET_OS_IPHONE
  19. // Compiling for iOS
  20. #if __IPHONE_OS_VERSION_MIN_REQUIRED >= 60000 // iOS 6.0 or later
  21. #define NEEDS_DISPATCH_RETAIN_RELEASE 0
  22. #else // iOS 5.X or earlier
  23. #define NEEDS_DISPATCH_RETAIN_RELEASE 1
  24. #endif
  25. #else
  26. // Compiling for Mac OS X
  27. #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1080 // Mac OS X 10.8 or later
  28. #define NEEDS_DISPATCH_RETAIN_RELEASE 0
  29. #else
  30. #define NEEDS_DISPATCH_RETAIN_RELEASE 1 // Mac OS X 10.7 or earlier
  31. #endif
  32. #endif
  33. #import "GCDAsyncUdpSocket.h"
  34. #if TARGET_OS_IPHONE
  35. #import <CFNetwork/CFNetwork.h>
  36. #import <UIKit/UIKit.h>
  37. #endif
  38. #import <arpa/inet.h>
  39. #import <fcntl.h>
  40. #import <ifaddrs.h>
  41. #import <netdb.h>
  42. #import <net/if.h>
  43. #import <sys/socket.h>
  44. #import <sys/types.h>
  45. #if 0
  46. // Logging Enabled - See log level below
  47. // Logging uses the CocoaLumberjack framework (which is also GCD based).
  48. // http://code.google.com/p/cocoalumberjack/
  49. //
  50. // It allows us to do a lot of logging without significantly slowing down the code.
  51. #import "DDLog.h"
  52. #define LogAsync NO
  53. #define LogContext 65535
  54. #define LogObjc(flg, frmt, ...) LOG_OBJC_MAYBE(LogAsync, logLevel, flg, LogContext, frmt, ##__VA_ARGS__)
  55. #define LogC(flg, frmt, ...) LOG_C_MAYBE(LogAsync, logLevel, flg, LogContext, frmt, ##__VA_ARGS__)
  56. #define LogError(frmt, ...) LogObjc(LOG_FLAG_ERROR, (@"%@: " frmt), THIS_FILE, ##__VA_ARGS__)
  57. #define LogWarn(frmt, ...) LogObjc(LOG_FLAG_WARN, (@"%@: " frmt), THIS_FILE, ##__VA_ARGS__)
  58. #define LogInfo(frmt, ...) LogObjc(LOG_FLAG_INFO, (@"%@: " frmt), THIS_FILE, ##__VA_ARGS__)
  59. #define LogVerbose(frmt, ...) LogObjc(LOG_FLAG_VERBOSE, (@"%@: " frmt), THIS_FILE, ##__VA_ARGS__)
  60. #define LogCError(frmt, ...) LogC(LOG_FLAG_ERROR, (@"%@: " frmt), THIS_FILE, ##__VA_ARGS__)
  61. #define LogCWarn(frmt, ...) LogC(LOG_FLAG_WARN, (@"%@: " frmt), THIS_FILE, ##__VA_ARGS__)
  62. #define LogCInfo(frmt, ...) LogC(LOG_FLAG_INFO, (@"%@: " frmt), THIS_FILE, ##__VA_ARGS__)
  63. #define LogCVerbose(frmt, ...) LogC(LOG_FLAG_VERBOSE, (@"%@: " frmt), THIS_FILE, ##__VA_ARGS__)
  64. #define LogTrace() LogObjc(LOG_FLAG_VERBOSE, @"%@: %@", THIS_FILE, THIS_METHOD)
  65. #define LogCTrace() LogC(LOG_FLAG_VERBOSE, @"%@: %s", THIS_FILE, __FUNCTION__)
  66. // Log levels : off, error, warn, info, verbose
  67. static const int logLevel = LOG_LEVEL_VERBOSE;
  68. #else
  69. // Logging Disabled
  70. #define LogError(frmt, ...) {}
  71. #define LogWarn(frmt, ...) {}
  72. #define LogInfo(frmt, ...) {}
  73. #define LogVerbose(frmt, ...) {}
  74. #define LogCError(frmt, ...) {}
  75. #define LogCWarn(frmt, ...) {}
  76. #define LogCInfo(frmt, ...) {}
  77. #define LogCVerbose(frmt, ...) {}
  78. #define LogTrace() {}
  79. #define LogCTrace(frmt, ...) {}
  80. #endif
  81. /**
  82. * Seeing a return statements within an inner block
  83. * can sometimes be mistaken for a return point of the enclosing method.
  84. * This makes inline blocks a bit easier to read.
  85. **/
  86. #define return_from_block return
  87. /**
  88. * A socket file descriptor is really just an integer.
  89. * It represents the index of the socket within the kernel.
  90. * This makes invalid file descriptor comparisons easier to read.
  91. **/
  92. #define SOCKET_NULL -1
  93. /**
  94. * Just to type less code.
  95. **/
  96. #define AutoreleasedBlock(block) ^{ @autoreleasepool { block(); }}
  97. @class GCDAsyncUdpSendPacket;
  98. NSString *const GCDAsyncUdpSocketException = @"GCDAsyncUdpSocketException";
  99. NSString *const GCDAsyncUdpSocketErrorDomain = @"GCDAsyncUdpSocketErrorDomain";
  100. NSString *const GCDAsyncUdpSocketQueueName = @"GCDAsyncUdpSocket";
  101. NSString *const GCDAsyncUdpSocketThreadName = @"GCDAsyncUdpSocket-CFStream";
  102. enum GCDAsyncUdpSocketFlags
  103. {
  104. kDidCreateSockets = 1 << 0, // If set, the sockets have been created.
  105. kDidBind = 1 << 1, // If set, bind has been called.
  106. kConnecting = 1 << 2, // If set, a connection attempt is in progress.
  107. kDidConnect = 1 << 3, // If set, socket is connected.
  108. kReceiveOnce = 1 << 4, // If set, one-at-a-time receive is enabled
  109. kReceiveContinuous = 1 << 5, // If set, continuous receive is enabled
  110. kIPv4Deactivated = 1 << 6, // If set, socket4 was closed due to bind or connect on IPv6.
  111. kIPv6Deactivated = 1 << 7, // If set, socket6 was closed due to bind or connect on IPv4.
  112. kSend4SourceSuspended = 1 << 8, // If set, send4Source is suspended.
  113. kSend6SourceSuspended = 1 << 9, // If set, send6Source is suspended.
  114. kReceive4SourceSuspended = 1 << 10, // If set, receive4Source is suspended.
  115. kReceive6SourceSuspended = 1 << 11, // If set, receive6Source is suspended.
  116. kSock4CanAcceptBytes = 1 << 12, // If set, we know socket4 can accept bytes. If unset, it's unknown.
  117. kSock6CanAcceptBytes = 1 << 13, // If set, we know socket6 can accept bytes. If unset, it's unknown.
  118. kForbidSendReceive = 1 << 14, // If set, no new send or receive operations are allowed to be queued.
  119. kCloseAfterSends = 1 << 15, // If set, close as soon as no more sends are queued.
  120. kFlipFlop = 1 << 16, // Used to alternate between IPv4 and IPv6 sockets.
  121. #if TARGET_OS_IPHONE
  122. kAddedStreamListener = 1 << 17, // If set, CFStreams have been added to listener thread
  123. #endif
  124. };
  125. enum GCDAsyncUdpSocketConfig
  126. {
  127. kIPv4Disabled = 1 << 0, // If set, IPv4 is disabled
  128. kIPv6Disabled = 1 << 1, // If set, IPv6 is disabled
  129. kPreferIPv4 = 1 << 2, // If set, IPv4 is preferred over IPv6
  130. kPreferIPv6 = 1 << 3, // If set, IPv6 is preferred over IPv4
  131. };
  132. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  133. #pragma mark -
  134. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  135. @interface GCDAsyncUdpSocket ()
  136. {
  137. id delegate;
  138. dispatch_queue_t delegateQueue;
  139. GCDAsyncUdpSocketReceiveFilterBlock receiveFilterBlock;
  140. dispatch_queue_t receiveFilterQueue;
  141. BOOL receiveFilterAsync;
  142. GCDAsyncUdpSocketSendFilterBlock sendFilterBlock;
  143. dispatch_queue_t sendFilterQueue;
  144. BOOL sendFilterAsync;
  145. uint32_t flags;
  146. uint16_t config;
  147. uint16_t max4ReceiveSize;
  148. uint32_t max6ReceiveSize;
  149. int socket4FD;
  150. int socket6FD;
  151. dispatch_queue_t socketQueue;
  152. dispatch_source_t send4Source;
  153. dispatch_source_t send6Source;
  154. dispatch_source_t receive4Source;
  155. dispatch_source_t receive6Source;
  156. dispatch_source_t sendTimer;
  157. GCDAsyncUdpSendPacket *currentSend;
  158. NSMutableArray *sendQueue;
  159. unsigned long socket4FDBytesAvailable;
  160. unsigned long socket6FDBytesAvailable;
  161. uint32_t pendingFilterOperations;
  162. NSData *cachedLocalAddress4;
  163. NSString *cachedLocalHost4;
  164. uint16_t cachedLocalPort4;
  165. NSData *cachedLocalAddress6;
  166. NSString *cachedLocalHost6;
  167. uint16_t cachedLocalPort6;
  168. NSData *cachedConnectedAddress;
  169. NSString *cachedConnectedHost;
  170. uint16_t cachedConnectedPort;
  171. int cachedConnectedFamily;
  172. #if TARGET_OS_IPHONE
  173. CFStreamClientContext streamContext;
  174. CFReadStreamRef readStream4;
  175. CFReadStreamRef readStream6;
  176. CFWriteStreamRef writeStream4;
  177. CFWriteStreamRef writeStream6;
  178. #endif
  179. id userData;
  180. }
  181. - (void)resumeSend4Source;
  182. - (void)resumeSend6Source;
  183. - (void)resumeReceive4Source;
  184. - (void)resumeReceive6Source;
  185. - (void)closeSockets;
  186. - (void)maybeConnect;
  187. - (BOOL)connectWithAddress4:(NSData *)address4 error:(NSError **)errPtr;
  188. - (BOOL)connectWithAddress6:(NSData *)address6 error:(NSError **)errPtr;
  189. - (void)maybeDequeueSend;
  190. - (void)doPreSend;
  191. - (void)doSend;
  192. - (void)endCurrentSend;
  193. - (void)setupSendTimerWithTimeout:(NSTimeInterval)timeout;
  194. - (void)doReceive;
  195. - (void)doReceiveEOF;
  196. - (void)closeWithError:(NSError *)error;
  197. - (BOOL)performMulticastRequest:(int)requestType forGroup:(NSString *)group onInterface:(NSString *)interface error:(NSError **)errPtr;
  198. #if TARGET_OS_IPHONE
  199. - (BOOL)createReadAndWriteStreams:(NSError **)errPtr;
  200. - (BOOL)registerForStreamCallbacks:(NSError **)errPtr;
  201. - (BOOL)addStreamsToRunLoop:(NSError **)errPtr;
  202. - (BOOL)openStreams:(NSError **)errPtr;
  203. - (void)removeStreamsFromRunLoop;
  204. - (void)closeReadAndWriteStreams;
  205. #endif
  206. + (NSString *)hostFromSockaddr4:(const struct sockaddr_in *)pSockaddr4;
  207. + (NSString *)hostFromSockaddr6:(const struct sockaddr_in6 *)pSockaddr6;
  208. + (uint16_t)portFromSockaddr4:(const struct sockaddr_in *)pSockaddr4;
  209. + (uint16_t)portFromSockaddr6:(const struct sockaddr_in6 *)pSockaddr6;
  210. #if TARGET_OS_IPHONE
  211. // Forward declaration
  212. + (void)listenerThread;
  213. #endif
  214. @end
  215. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  216. #pragma mark -
  217. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  218. /**
  219. * The GCDAsyncUdpSendPacket encompasses the instructions for a single send/write.
  220. **/
  221. @interface GCDAsyncUdpSendPacket : NSObject {
  222. @public
  223. NSData *buffer;
  224. NSTimeInterval timeout;
  225. long tag;
  226. BOOL resolveInProgress;
  227. BOOL filterInProgress;
  228. NSArray *resolvedAddresses;
  229. NSError *resolveError;
  230. NSData *address;
  231. int addressFamily;
  232. }
  233. - (id)initWithData:(NSData *)d timeout:(NSTimeInterval)t tag:(long)i;
  234. @end
  235. @implementation GCDAsyncUdpSendPacket
  236. - (id)initWithData:(NSData *)d timeout:(NSTimeInterval)t tag:(long)i
  237. {
  238. if ((self = [super init]))
  239. {
  240. buffer = d;
  241. timeout = t;
  242. tag = i;
  243. resolveInProgress = NO;
  244. }
  245. return self;
  246. }
  247. @end
  248. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  249. #pragma mark -
  250. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  251. @interface GCDAsyncUdpSpecialPacket : NSObject {
  252. @public
  253. // uint8_t type;
  254. BOOL resolveInProgress;
  255. NSArray *addresses;
  256. NSError *error;
  257. }
  258. - (id)init;
  259. @end
  260. @implementation GCDAsyncUdpSpecialPacket
  261. - (id)init
  262. {
  263. self = [super init];
  264. return self;
  265. }
  266. @end
  267. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  268. #pragma mark -
  269. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  270. @implementation GCDAsyncUdpSocket
  271. - (id)init
  272. {
  273. LogTrace();
  274. return [self initWithDelegate:nil delegateQueue:NULL socketQueue:NULL];
  275. }
  276. - (id)initWithSocketQueue:(dispatch_queue_t)sq
  277. {
  278. LogTrace();
  279. return [self initWithDelegate:nil delegateQueue:NULL socketQueue:sq];
  280. }
  281. - (id)initWithDelegate:(id)aDelegate delegateQueue:(dispatch_queue_t)dq
  282. {
  283. LogTrace();
  284. return [self initWithDelegate:aDelegate delegateQueue:dq socketQueue:NULL];
  285. }
  286. - (id)initWithDelegate:(id)aDelegate delegateQueue:(dispatch_queue_t)dq socketQueue:(dispatch_queue_t)sq
  287. {
  288. LogTrace();
  289. if ((self = [super init]))
  290. {
  291. delegate = aDelegate;
  292. if (dq)
  293. {
  294. delegateQueue = dq;
  295. #if NEEDS_DISPATCH_RETAIN_RELEASE
  296. dispatch_retain(delegateQueue);
  297. #endif
  298. }
  299. max4ReceiveSize = 9216;
  300. max6ReceiveSize = 9216;
  301. socket4FD = SOCKET_NULL;
  302. socket6FD = SOCKET_NULL;
  303. if (sq)
  304. {
  305. NSAssert(sq != dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0),
  306. @"The given socketQueue parameter must not be a concurrent queue.");
  307. NSAssert(sq != dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0),
  308. @"The given socketQueue parameter must not be a concurrent queue.");
  309. NSAssert(sq != dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),
  310. @"The given socketQueue parameter must not be a concurrent queue.");
  311. socketQueue = sq;
  312. #if NEEDS_DISPATCH_RETAIN_RELEASE
  313. dispatch_retain(socketQueue);
  314. #endif
  315. }
  316. else
  317. {
  318. socketQueue = dispatch_queue_create([GCDAsyncUdpSocketQueueName UTF8String], NULL);
  319. }
  320. currentSend = nil;
  321. sendQueue = [[NSMutableArray alloc] initWithCapacity:5];
  322. #if TARGET_OS_IPHONE
  323. [[NSNotificationCenter defaultCenter] addObserver:self
  324. selector:@selector(applicationWillEnterForeground:)
  325. name:UIApplicationWillEnterForegroundNotification
  326. object:nil];
  327. #endif
  328. }
  329. return self;
  330. }
  331. - (void)dealloc
  332. {
  333. LogInfo(@"%@ - %@ (start)", THIS_METHOD, self);
  334. #if TARGET_OS_IPHONE
  335. [[NSNotificationCenter defaultCenter] removeObserver:self];
  336. #endif
  337. if (dispatch_get_current_queue() == socketQueue)
  338. {
  339. [self closeWithError:nil];
  340. }
  341. else
  342. {
  343. dispatch_sync(socketQueue, ^{
  344. [self closeWithError:nil];
  345. });
  346. }
  347. delegate = nil;
  348. #if NEEDS_DISPATCH_RETAIN_RELEASE
  349. if (delegateQueue) dispatch_release(delegateQueue);
  350. #endif
  351. delegateQueue = NULL;
  352. #if NEEDS_DISPATCH_RETAIN_RELEASE
  353. if (socketQueue) dispatch_release(socketQueue);
  354. #endif
  355. socketQueue = NULL;
  356. LogInfo(@"%@ - %@ (finish)", THIS_METHOD, self);
  357. }
  358. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  359. #pragma mark Configuration
  360. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  361. - (id)delegate
  362. {
  363. if (dispatch_get_current_queue() == socketQueue)
  364. {
  365. return delegate;
  366. }
  367. else
  368. {
  369. __block id result = nil;
  370. dispatch_sync(socketQueue, ^{
  371. result = delegate;
  372. });
  373. return result;
  374. }
  375. }
  376. - (void)setDelegate:(id)newDelegate synchronously:(BOOL)synchronously
  377. {
  378. dispatch_block_t block = ^{
  379. delegate = newDelegate;
  380. };
  381. if (dispatch_get_current_queue() == socketQueue) {
  382. block();
  383. }
  384. else {
  385. if (synchronously)
  386. dispatch_sync(socketQueue, block);
  387. else
  388. dispatch_async(socketQueue, block);
  389. }
  390. }
  391. - (void)setDelegate:(id)newDelegate
  392. {
  393. [self setDelegate:newDelegate synchronously:NO];
  394. }
  395. - (void)synchronouslySetDelegate:(id)newDelegate
  396. {
  397. [self setDelegate:newDelegate synchronously:YES];
  398. }
  399. - (dispatch_queue_t)delegateQueue
  400. {
  401. if (dispatch_get_current_queue() == socketQueue)
  402. {
  403. return delegateQueue;
  404. }
  405. else
  406. {
  407. __block dispatch_queue_t result = NULL;
  408. dispatch_sync(socketQueue, ^{
  409. result = delegateQueue;
  410. });
  411. return result;
  412. }
  413. }
  414. - (void)setDelegateQueue:(dispatch_queue_t)newDelegateQueue synchronously:(BOOL)synchronously
  415. {
  416. dispatch_block_t block = ^{
  417. #if NEEDS_DISPATCH_RETAIN_RELEASE
  418. if (delegateQueue) dispatch_release(delegateQueue);
  419. if (newDelegateQueue) dispatch_retain(newDelegateQueue);
  420. #endif
  421. delegateQueue = newDelegateQueue;
  422. };
  423. if (dispatch_get_current_queue() == socketQueue) {
  424. block();
  425. }
  426. else {
  427. if (synchronously)
  428. dispatch_sync(socketQueue, block);
  429. else
  430. dispatch_async(socketQueue, block);
  431. }
  432. }
  433. - (void)setDelegateQueue:(dispatch_queue_t)newDelegateQueue
  434. {
  435. [self setDelegateQueue:newDelegateQueue synchronously:NO];
  436. }
  437. - (void)synchronouslySetDelegateQueue:(dispatch_queue_t)newDelegateQueue
  438. {
  439. [self setDelegateQueue:newDelegateQueue synchronously:YES];
  440. }
  441. - (void)getDelegate:(id *)delegatePtr delegateQueue:(dispatch_queue_t *)delegateQueuePtr
  442. {
  443. if (dispatch_get_current_queue() == socketQueue)
  444. {
  445. if (delegatePtr) *delegatePtr = delegate;
  446. if (delegateQueuePtr) *delegateQueuePtr = delegateQueue;
  447. }
  448. else
  449. {
  450. __block id dPtr = NULL;
  451. __block dispatch_queue_t dqPtr = NULL;
  452. dispatch_sync(socketQueue, ^{
  453. dPtr = delegate;
  454. dqPtr = delegateQueue;
  455. });
  456. if (delegatePtr) *delegatePtr = dPtr;
  457. if (delegateQueuePtr) *delegateQueuePtr = dqPtr;
  458. }
  459. }
  460. - (void)setDelegate:(id)newDelegate delegateQueue:(dispatch_queue_t)newDelegateQueue synchronously:(BOOL)synchronously
  461. {
  462. dispatch_block_t block = ^{
  463. delegate = newDelegate;
  464. #if NEEDS_DISPATCH_RETAIN_RELEASE
  465. if (delegateQueue) dispatch_release(delegateQueue);
  466. if (newDelegateQueue) dispatch_retain(newDelegateQueue);
  467. #endif
  468. delegateQueue = newDelegateQueue;
  469. };
  470. if (dispatch_get_current_queue() == socketQueue) {
  471. block();
  472. }
  473. else {
  474. if (synchronously)
  475. dispatch_sync(socketQueue, block);
  476. else
  477. dispatch_async(socketQueue, block);
  478. }
  479. }
  480. - (void)setDelegate:(id)newDelegate delegateQueue:(dispatch_queue_t)newDelegateQueue
  481. {
  482. [self setDelegate:newDelegate delegateQueue:newDelegateQueue synchronously:NO];
  483. }
  484. - (void)synchronouslySetDelegate:(id)newDelegate delegateQueue:(dispatch_queue_t)newDelegateQueue
  485. {
  486. [self setDelegate:newDelegate delegateQueue:newDelegateQueue synchronously:YES];
  487. }
  488. - (BOOL)isIPv4Enabled
  489. {
  490. // Note: YES means kIPv4Disabled is OFF
  491. __block BOOL result = NO;
  492. dispatch_block_t block = ^{
  493. result = ((config & kIPv4Disabled) == 0);
  494. };
  495. if (dispatch_get_current_queue() == socketQueue)
  496. block();
  497. else
  498. dispatch_sync(socketQueue, block);
  499. return result;
  500. }
  501. - (void)setIPv4Enabled:(BOOL)flag
  502. {
  503. // Note: YES means kIPv4Disabled is OFF
  504. dispatch_block_t block = ^{
  505. LogVerbose(@"%@ %@", THIS_METHOD, (flag ? @"YES" : @"NO"));
  506. if (flag)
  507. config &= ~kIPv4Disabled;
  508. else
  509. config |= kIPv4Disabled;
  510. };
  511. if (dispatch_get_current_queue() == socketQueue)
  512. block();
  513. else
  514. dispatch_async(socketQueue, block);
  515. }
  516. - (BOOL)isIPv6Enabled
  517. {
  518. // Note: YES means kIPv6Disabled is OFF
  519. __block BOOL result = NO;
  520. dispatch_block_t block = ^{
  521. result = ((config & kIPv6Disabled) == 0);
  522. };
  523. if (dispatch_get_current_queue() == socketQueue)
  524. block();
  525. else
  526. dispatch_sync(socketQueue, block);
  527. return result;
  528. }
  529. - (void)setIPv6Enabled:(BOOL)flag
  530. {
  531. // Note: YES means kIPv6Disabled is OFF
  532. dispatch_block_t block = ^{
  533. LogVerbose(@"%@ %@", THIS_METHOD, (flag ? @"YES" : @"NO"));
  534. if (flag)
  535. config &= ~kIPv6Disabled;
  536. else
  537. config |= kIPv6Disabled;
  538. };
  539. if (dispatch_get_current_queue() == socketQueue)
  540. block();
  541. else
  542. dispatch_async(socketQueue, block);
  543. }
  544. - (BOOL)isIPv4Preferred
  545. {
  546. __block BOOL result = NO;
  547. dispatch_block_t block = ^{
  548. result = (config & kPreferIPv4) ? YES : NO;
  549. };
  550. if (dispatch_get_current_queue() == socketQueue)
  551. block();
  552. else
  553. dispatch_sync(socketQueue, block);
  554. return result;
  555. }
  556. - (BOOL)isIPv6Preferred
  557. {
  558. __block BOOL result = NO;
  559. dispatch_block_t block = ^{
  560. result = (config & kPreferIPv6) ? YES : NO;
  561. };
  562. if (dispatch_get_current_queue() == socketQueue)
  563. block();
  564. else
  565. dispatch_sync(socketQueue, block);
  566. return result;
  567. }
  568. - (BOOL)isIPVersionNeutral
  569. {
  570. __block BOOL result = NO;
  571. dispatch_block_t block = ^{
  572. result = (config & (kPreferIPv4 | kPreferIPv6)) == 0;
  573. };
  574. if (dispatch_get_current_queue() == socketQueue)
  575. block();
  576. else
  577. dispatch_sync(socketQueue, block);
  578. return result;
  579. }
  580. - (void)setPreferIPv4
  581. {
  582. dispatch_block_t block = ^{
  583. LogTrace();
  584. config |= kPreferIPv4;
  585. config &= ~kPreferIPv6;
  586. };
  587. if (dispatch_get_current_queue() == socketQueue)
  588. block();
  589. else
  590. dispatch_async(socketQueue, block);
  591. }
  592. - (void)setPreferIPv6
  593. {
  594. dispatch_block_t block = ^{
  595. LogTrace();
  596. config &= ~kPreferIPv4;
  597. config |= kPreferIPv6;
  598. };
  599. if (dispatch_get_current_queue() == socketQueue)
  600. block();
  601. else
  602. dispatch_async(socketQueue, block);
  603. }
  604. - (void)setIPVersionNeutral
  605. {
  606. dispatch_block_t block = ^{
  607. LogTrace();
  608. config &= ~kPreferIPv4;
  609. config &= ~kPreferIPv6;
  610. };
  611. if (dispatch_get_current_queue() == socketQueue)
  612. block();
  613. else
  614. dispatch_async(socketQueue, block);
  615. }
  616. - (uint16_t)maxReceiveIPv4BufferSize
  617. {
  618. __block uint16_t result = 0;
  619. dispatch_block_t block = ^{
  620. result = max4ReceiveSize;
  621. };
  622. if (dispatch_get_current_queue() == socketQueue)
  623. block();
  624. else
  625. dispatch_sync(socketQueue, block);
  626. return result;
  627. }
  628. - (void)setMaxReceiveIPv4BufferSize:(uint16_t)max
  629. {
  630. dispatch_block_t block = ^{
  631. LogVerbose(@"%@ %u", THIS_METHOD, (unsigned)max);
  632. max4ReceiveSize = max;
  633. };
  634. if (dispatch_get_current_queue() == socketQueue)
  635. block();
  636. else
  637. dispatch_async(socketQueue, block);
  638. }
  639. - (uint32_t)maxReceiveIPv6BufferSize
  640. {
  641. __block uint32_t result = 0;
  642. dispatch_block_t block = ^{
  643. result = max6ReceiveSize;
  644. };
  645. if (dispatch_get_current_queue() == socketQueue)
  646. block();
  647. else
  648. dispatch_sync(socketQueue, block);
  649. return result;
  650. }
  651. - (void)setMaxReceiveIPv6BufferSize:(uint32_t)max
  652. {
  653. dispatch_block_t block = ^{
  654. LogVerbose(@"%@ %u", THIS_METHOD, (unsigned)max);
  655. max6ReceiveSize = max;
  656. };
  657. if (dispatch_get_current_queue() == socketQueue)
  658. block();
  659. else
  660. dispatch_async(socketQueue, block);
  661. }
  662. - (id)userData
  663. {
  664. __block id result = nil;
  665. dispatch_block_t block = ^{
  666. result = userData;
  667. };
  668. if (dispatch_get_current_queue() == socketQueue)
  669. block();
  670. else
  671. dispatch_sync(socketQueue, block);
  672. return result;
  673. }
  674. - (void)setUserData:(id)arbitraryUserData
  675. {
  676. dispatch_block_t block = ^{
  677. if (userData != arbitraryUserData)
  678. {
  679. userData = arbitraryUserData;
  680. }
  681. };
  682. if (dispatch_get_current_queue() == socketQueue)
  683. block();
  684. else
  685. dispatch_async(socketQueue, block);
  686. }
  687. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  688. #pragma mark Delegate Helpers
  689. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  690. - (void)notifyDidConnectToAddress:(NSData *)anAddress
  691. {
  692. LogTrace();
  693. if (delegateQueue && [delegate respondsToSelector:@selector(udpSocket:didConnectToAddress:)])
  694. {
  695. id theDelegate = delegate;
  696. NSData *address = [anAddress copy]; // In case param is NSMutableData
  697. dispatch_async(delegateQueue, ^{ @autoreleasepool {
  698. [theDelegate udpSocket:self didConnectToAddress:address];
  699. }});
  700. }
  701. }
  702. - (void)notifyDidNotConnect:(NSError *)error
  703. {
  704. LogTrace();
  705. if (delegateQueue && [delegate respondsToSelector:@selector(udpSocket:didNotConnect:)])
  706. {
  707. id theDelegate = delegate;
  708. dispatch_async(delegateQueue, ^{ @autoreleasepool {
  709. [theDelegate udpSocket:self didNotConnect:error];
  710. }});
  711. }
  712. }
  713. - (void)notifyDidSendDataWithTag:(long)tag
  714. {
  715. LogTrace();
  716. if (delegateQueue && [delegate respondsToSelector:@selector(udpSocket:didSendDataWithTag:)])
  717. {
  718. id theDelegate = delegate;
  719. dispatch_async(delegateQueue, ^{ @autoreleasepool {
  720. [theDelegate udpSocket:self didSendDataWithTag:tag];
  721. }});
  722. }
  723. }
  724. - (void)notifyDidNotSendDataWithTag:(long)tag dueToError:(NSError *)error
  725. {
  726. LogTrace();
  727. if (delegateQueue && [delegate respondsToSelector:@selector(udpSocket:didNotSendDataWithTag:dueToError:)])
  728. {
  729. id theDelegate = delegate;
  730. dispatch_async(delegateQueue, ^{ @autoreleasepool {
  731. [theDelegate udpSocket:self didNotSendDataWithTag:tag dueToError:error];
  732. }});
  733. }
  734. }
  735. - (void)notifyDidReceiveData:(NSData *)data fromAddress:(NSData *)address withFilterContext:(id)context
  736. {
  737. LogTrace();
  738. SEL selector = @selector(udpSocket:didReceiveData:fromAddress:withFilterContext:);
  739. if (delegateQueue && [delegate respondsToSelector:selector])
  740. {
  741. id theDelegate = delegate;
  742. dispatch_async(delegateQueue, ^{ @autoreleasepool {
  743. [theDelegate udpSocket:self didReceiveData:data fromAddress:address withFilterContext:context];
  744. }});
  745. }
  746. }
  747. - (void)notifyDidCloseWithError:(NSError *)error
  748. {
  749. LogTrace();
  750. if (delegateQueue && [delegate respondsToSelector:@selector(udpSocketDidClose:withError:)])
  751. {
  752. id theDelegate = delegate;
  753. dispatch_async(delegateQueue, ^{ @autoreleasepool {
  754. [theDelegate udpSocketDidClose:self withError:error];
  755. }});
  756. }
  757. }
  758. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  759. #pragma mark Errors
  760. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  761. - (NSError *)badConfigError:(NSString *)errMsg
  762. {
  763. NSDictionary *userInfo = [NSDictionary dictionaryWithObject:errMsg forKey:NSLocalizedDescriptionKey];
  764. return [NSError errorWithDomain:GCDAsyncUdpSocketErrorDomain
  765. code:GCDAsyncUdpSocketBadConfigError
  766. userInfo:userInfo];
  767. }
  768. - (NSError *)badParamError:(NSString *)errMsg
  769. {
  770. NSDictionary *userInfo = [NSDictionary dictionaryWithObject:errMsg forKey:NSLocalizedDescriptionKey];
  771. return [NSError errorWithDomain:GCDAsyncUdpSocketErrorDomain
  772. code:GCDAsyncUdpSocketBadParamError
  773. userInfo:userInfo];
  774. }
  775. - (NSError *)gaiError:(int)gai_error
  776. {
  777. NSString *errMsg = [NSString stringWithCString:gai_strerror(gai_error) encoding:NSASCIIStringEncoding];
  778. NSDictionary *userInfo = [NSDictionary dictionaryWithObject:errMsg forKey:NSLocalizedDescriptionKey];
  779. return [NSError errorWithDomain:@"kCFStreamErrorDomainNetDB" code:gai_error userInfo:userInfo];
  780. }
  781. - (NSError *)errnoErrorWithReason:(NSString *)reason
  782. {
  783. NSString *errMsg = [NSString stringWithUTF8String:strerror(errno)];
  784. NSDictionary *userInfo;
  785. if (reason)
  786. userInfo = [NSDictionary dictionaryWithObjectsAndKeys:errMsg, NSLocalizedDescriptionKey,
  787. reason, NSLocalizedFailureReasonErrorKey, nil];
  788. else
  789. userInfo = [NSDictionary dictionaryWithObjectsAndKeys:errMsg, NSLocalizedDescriptionKey, nil];
  790. return [NSError errorWithDomain:NSPOSIXErrorDomain code:errno userInfo:userInfo];
  791. }
  792. - (NSError *)errnoError
  793. {
  794. return [self errnoErrorWithReason:nil];
  795. }
  796. /**
  797. * Returns a standard send timeout error.
  798. **/
  799. - (NSError *)sendTimeoutError
  800. {
  801. NSString *errMsg = NSLocalizedStringWithDefaultValue(@"GCDAsyncUdpSocketSendTimeoutError",
  802. @"GCDAsyncUdpSocket", [NSBundle mainBundle],
  803. @"Send operation timed out", nil);
  804. NSDictionary *userInfo = [NSDictionary dictionaryWithObject:errMsg forKey:NSLocalizedDescriptionKey];
  805. return [NSError errorWithDomain:GCDAsyncUdpSocketErrorDomain
  806. code:GCDAsyncUdpSocketSendTimeoutError
  807. userInfo:userInfo];
  808. }
  809. - (NSError *)socketClosedError
  810. {
  811. NSString *errMsg = NSLocalizedStringWithDefaultValue(@"GCDAsyncUdpSocketClosedError",
  812. @"GCDAsyncUdpSocket", [NSBundle mainBundle],
  813. @"Socket closed", nil);
  814. NSDictionary *userInfo = [NSDictionary dictionaryWithObject:errMsg forKey:NSLocalizedDescriptionKey];
  815. return [NSError errorWithDomain:GCDAsyncUdpSocketErrorDomain code:GCDAsyncUdpSocketClosedError userInfo:userInfo];
  816. }
  817. - (NSError *)otherError:(NSString *)errMsg
  818. {
  819. NSDictionary *userInfo = [NSDictionary dictionaryWithObject:errMsg forKey:NSLocalizedDescriptionKey];
  820. return [NSError errorWithDomain:GCDAsyncUdpSocketErrorDomain
  821. code:GCDAsyncUdpSocketOtherError
  822. userInfo:userInfo];
  823. }
  824. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  825. #pragma mark Utilities
  826. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  827. - (BOOL)preOp:(NSError **)errPtr
  828. {
  829. NSAssert(dispatch_get_current_queue() == socketQueue, @"Must be dispatched on socketQueue");
  830. if (delegate == nil) // Must have delegate set
  831. {
  832. if (errPtr)
  833. {
  834. NSString *msg = @"Attempting to use socket without a delegate. Set a delegate first.";
  835. *errPtr = [self badConfigError:msg];
  836. }
  837. return NO;
  838. }
  839. if (delegateQueue == NULL) // Must have delegate queue set
  840. {
  841. if (errPtr)
  842. {
  843. NSString *msg = @"Attempting to use socket without a delegate queue. Set a delegate queue first.";
  844. *errPtr = [self badConfigError:msg];
  845. }
  846. return NO;
  847. }
  848. return YES;
  849. }
  850. /**
  851. * This method executes on a global concurrent queue.
  852. * When complete, it executes the given completion block on the socketQueue.
  853. **/
  854. - (void)asyncResolveHost:(NSString *)aHost
  855. port:(uint16_t)port
  856. withCompletionBlock:(void (^)(NSArray *addresses, NSError *error))completionBlock
  857. {
  858. LogTrace();
  859. // Check parameter(s)
  860. if (aHost == nil)
  861. {
  862. NSString *msg = @"The host param is nil. Should be domain name or IP address string.";
  863. NSError *error = [self badParamError:msg];
  864. // We should still use dispatch_async since this method is expected to be asynchronous
  865. dispatch_async(socketQueue, ^{ @autoreleasepool {
  866. completionBlock(nil, error);
  867. }});
  868. return;
  869. }
  870. // It's possible that the given aHost parameter is actually a NSMutableString.
  871. // So we want to copy it now, within this block that will be executed synchronously.
  872. // This way the asynchronous lookup block below doesn't have to worry about it changing.
  873. NSString *host = [aHost copy];
  874. dispatch_queue_t globalConcurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
  875. dispatch_async(globalConcurrentQueue, ^{ @autoreleasepool {
  876. NSMutableArray *addresses = [NSMutableArray arrayWithCapacity:2];
  877. NSError *error = nil;
  878. if ([host isEqualToString:@"localhost"] || [host isEqualToString:@"loopback"])
  879. {
  880. // Use LOOPBACK address
  881. struct sockaddr_in sockaddr4;
  882. memset(&sockaddr4, 0, sizeof(sockaddr4));
  883. sockaddr4.sin_len = sizeof(struct sockaddr_in);
  884. sockaddr4.sin_family = AF_INET;
  885. sockaddr4.sin_port = htons(port);
  886. sockaddr4.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
  887. struct sockaddr_in6 sockaddr6;
  888. memset(&sockaddr6, 0, sizeof(sockaddr6));
  889. sockaddr6.sin6_len = sizeof(struct sockaddr_in6);
  890. sockaddr6.sin6_family = AF_INET6;
  891. sockaddr6.sin6_port = htons(port);
  892. sockaddr6.sin6_addr = in6addr_loopback;
  893. // Wrap the native address structures and add to list
  894. [addresses addObject:[NSData dataWithBytes:&sockaddr4 length:sizeof(sockaddr4)]];
  895. [addresses addObject:[NSData dataWithBytes:&sockaddr6 length:sizeof(sockaddr6)]];
  896. }
  897. else
  898. {
  899. NSString *portStr = [NSString stringWithFormat:@"%hu", port];
  900. struct addrinfo hints, *res, *res0;
  901. memset(&hints, 0, sizeof(hints));
  902. hints.ai_family = PF_UNSPEC;
  903. hints.ai_socktype = SOCK_DGRAM;
  904. hints.ai_protocol = IPPROTO_UDP;
  905. int gai_error = getaddrinfo([host UTF8String], [portStr UTF8String], &hints, &res0);
  906. if (gai_error)
  907. {
  908. error = [self gaiError:gai_error];
  909. }
  910. else
  911. {
  912. for(res = res0; res; res = res->ai_next)
  913. {
  914. if (res->ai_family == AF_INET)
  915. {
  916. // Found IPv4 address
  917. // Wrap the native address structure and add to list
  918. [addresses addObject:[NSData dataWithBytes:res->ai_addr length:res->ai_addrlen]];
  919. }
  920. else if (res->ai_family == AF_INET6)
  921. {
  922. // Found IPv6 address
  923. // Wrap the native address structure and add to list
  924. [addresses addObject:[NSData dataWithBytes:res->ai_addr length:res->ai_addrlen]];
  925. }
  926. }
  927. freeaddrinfo(res0);
  928. if ([addresses count] == 0)
  929. {
  930. error = [self gaiError:EAI_FAIL];
  931. }
  932. }
  933. }
  934. dispatch_async(socketQueue, ^{ @autoreleasepool {
  935. completionBlock(addresses, error);
  936. }});
  937. }});
  938. }
  939. /**
  940. * This method picks an address from the given list of addresses.
  941. * The address picked depends upon which protocols are disabled, deactived, & preferred.
  942. *
  943. * Returns the address family (AF_INET or AF_INET6) of the picked address,
  944. * or AF_UNSPEC and the corresponding error is there's a problem.
  945. **/
  946. - (int)getAddress:(NSData **)addressPtr error:(NSError **)errorPtr fromAddresses:(NSArray *)addresses
  947. {
  948. NSAssert(dispatch_get_current_queue() == socketQueue, @"Must be dispatched on socketQueue");
  949. NSAssert([addresses count] > 0, @"Expected at least one address");
  950. int resultAF = AF_UNSPEC;
  951. NSData *resultAddress = nil;
  952. NSError *resultError = nil;
  953. // Check for problems
  954. BOOL resolvedIPv4Address = NO;
  955. BOOL resolvedIPv6Address = NO;
  956. for (NSData *address in addresses)
  957. {
  958. switch ([[self class] familyFromAddress:address])
  959. {
  960. case AF_INET : resolvedIPv4Address = YES; break;
  961. case AF_INET6 : resolvedIPv6Address = YES; break;
  962. default : NSAssert(NO, @"Addresses array contains invalid address");
  963. }
  964. }
  965. BOOL isIPv4Disabled = (config & kIPv4Disabled) ? YES : NO;
  966. BOOL isIPv6Disabled = (config & kIPv6Disabled) ? YES : NO;
  967. if (isIPv4Disabled && !resolvedIPv6Address)
  968. {
  969. NSString *msg = @"IPv4 has been disabled and DNS lookup found no IPv6 address(es).";
  970. resultError = [self otherError:msg];
  971. if (addressPtr) *addressPtr = resultAddress;
  972. if (errorPtr) *errorPtr = resultError;
  973. return resultAF;
  974. }
  975. if (isIPv6Disabled && !resolvedIPv4Address)
  976. {
  977. NSString *msg = @"IPv6 has been disabled and DNS lookup found no IPv4 address(es).";
  978. resultError = [self otherError:msg];
  979. if (addressPtr) *addressPtr = resultAddress;
  980. if (errorPtr) *errorPtr = resultError;
  981. return resultAF;
  982. }
  983. BOOL isIPv4Deactivated = (flags & kIPv4Deactivated) ? YES : NO;
  984. BOOL isIPv6Deactivated = (flags & kIPv6Deactivated) ? YES : NO;
  985. if (isIPv4Deactivated && !resolvedIPv6Address)
  986. {
  987. NSString *msg = @"IPv4 has been deactivated due to bind/connect, and DNS lookup found no IPv6 address(es).";
  988. resultError = [self otherError:msg];
  989. if (addressPtr) *addressPtr = resultAddress;
  990. if (errorPtr) *errorPtr = resultError;
  991. return resultAF;
  992. }
  993. if (isIPv6Deactivated && !resolvedIPv4Address)
  994. {
  995. NSString *msg = @"IPv6 has been deactivated due to bind/connect, and DNS lookup found no IPv4 address(es).";
  996. resultError = [self otherError:msg];
  997. if (addressPtr) *addressPtr = resultAddress;
  998. if (errorPtr) *errorPtr = resultError;
  999. return resultAF;
  1000. }
  1001. // Extract first IPv4 and IPv6 address in list
  1002. BOOL ipv4WasFirstInList = YES;
  1003. NSData *address4 = nil;
  1004. NSData *address6 = nil;
  1005. for (NSData *address in addresses)
  1006. {
  1007. int af = [[self class] familyFromAddress:address];
  1008. if (af == AF_INET)
  1009. {
  1010. if (address4 == nil)
  1011. {
  1012. address4 = address;
  1013. if (address6)
  1014. break;
  1015. else
  1016. ipv4WasFirstInList = YES;
  1017. }
  1018. }
  1019. else // af == AF_INET6
  1020. {
  1021. if (address6 == nil)
  1022. {
  1023. address6 = address;
  1024. if (address4)
  1025. break;
  1026. else
  1027. ipv4WasFirstInList = NO;
  1028. }
  1029. }
  1030. }
  1031. // Determine socket type
  1032. BOOL preferIPv4 = (config & kPreferIPv4) ? YES : NO;
  1033. BOOL preferIPv6 = (config & kPreferIPv6) ? YES : NO;
  1034. BOOL useIPv4 = ((preferIPv4 && address4) || (address6 == nil));
  1035. BOOL useIPv6 = ((preferIPv6 && address6) || (address4 == nil));
  1036. NSAssert(!(preferIPv4 && preferIPv6), @"Invalid config state");
  1037. NSAssert(!(useIPv4 && useIPv6), @"Invalid logic");
  1038. if (useIPv4 || (!useIPv6 && ipv4WasFirstInList))
  1039. {
  1040. resultAF = AF_INET;
  1041. resultAddress = address4;
  1042. }
  1043. else
  1044. {
  1045. resultAF = AF_INET6;
  1046. resultAddress = address6;
  1047. }
  1048. if (addressPtr) *addressPtr = resultAddress;
  1049. if (errorPtr) *errorPtr = resultError;
  1050. return resultAF;
  1051. }
  1052. /**
  1053. * Finds the address(es) of an interface description.
  1054. * An inteface description may be an interface name (en0, en1, lo0) or corresponding IP (192.168.4.34).
  1055. **/
  1056. - (void)convertIntefaceDescription:(NSString *)interfaceDescription
  1057. port:(uint16_t)port
  1058. intoAddress4:(NSData **)interfaceAddr4Ptr
  1059. address6:(NSData **)interfaceAddr6Ptr
  1060. {
  1061. NSData *addr4 = nil;
  1062. NSData *addr6 = nil;
  1063. if (interfaceDescription == nil)
  1064. {
  1065. // ANY address
  1066. struct sockaddr_in sockaddr4;
  1067. memset(&sockaddr4, 0, sizeof(sockaddr4));
  1068. sockaddr4.sin_len = sizeof(sockaddr4);
  1069. sockaddr4.sin_family = AF_INET;
  1070. sockaddr4.sin_port = htons(port);
  1071. sockaddr4.sin_addr.s_addr = htonl(INADDR_ANY);
  1072. struct sockaddr_in6 sockaddr6;
  1073. memset(&sockaddr6, 0, sizeof(sockaddr6));
  1074. sockaddr6.sin6_len = sizeof(sockaddr6);
  1075. sockaddr6.sin6_family = AF_INET6;
  1076. sockaddr6.sin6_port = htons(port);
  1077. sockaddr6.sin6_addr = in6addr_any;
  1078. addr4 = [NSData dataWithBytes:&sockaddr4 length:sizeof(sockaddr4)];
  1079. addr6 = [NSData dataWithBytes:&sockaddr6 length:sizeof(sockaddr6)];
  1080. }
  1081. else if ([interfaceDescription isEqualToString:@"localhost"] ||
  1082. [interfaceDescription isEqualToString:@"loopback"])
  1083. {
  1084. // LOOPBACK address
  1085. struct sockaddr_in sockaddr4;
  1086. memset(&sockaddr4, 0, sizeof(sockaddr4));
  1087. sockaddr4.sin_len = sizeof(struct sockaddr_in);
  1088. sockaddr4.sin_family = AF_INET;
  1089. sockaddr4.sin_port = htons(port);
  1090. sockaddr4.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
  1091. struct sockaddr_in6 sockaddr6;
  1092. memset(&sockaddr6, 0, sizeof(sockaddr6));
  1093. sockaddr6.sin6_len = sizeof(struct sockaddr_in6);
  1094. sockaddr6.sin6_family = AF_INET6;
  1095. sockaddr6.sin6_port = htons(port);
  1096. sockaddr6.sin6_addr = in6addr_loopback;
  1097. addr4 = [NSData dataWithBytes:&sockaddr4 length:sizeof(sockaddr4)];
  1098. addr6 = [NSData dataWithBytes:&sockaddr6 length:sizeof(sockaddr6)];
  1099. }
  1100. else
  1101. {
  1102. const char *iface = [interfaceDescription UTF8String];
  1103. struct ifaddrs *addrs;
  1104. const struct ifaddrs *cursor;
  1105. if ((getifaddrs(&addrs) == 0))
  1106. {
  1107. cursor = addrs;
  1108. while (cursor != NULL)
  1109. {
  1110. if ((addr4 == nil) && (cursor->ifa_addr->sa_family == AF_INET))
  1111. {
  1112. // IPv4
  1113. struct sockaddr_in *addr = (struct sockaddr_in *)cursor->ifa_addr;
  1114. if (strcmp(cursor->ifa_name, iface) == 0)
  1115. {
  1116. // Name match
  1117. struct sockaddr_in nativeAddr4 = *addr;
  1118. nativeAddr4.sin_port = htons(port);
  1119. addr4 = [NSData dataWithBytes:&nativeAddr4 length:sizeof(nativeAddr4)];
  1120. }
  1121. else
  1122. {
  1123. char ip[INET_ADDRSTRLEN];
  1124. const char *conversion;
  1125. conversion = inet_ntop(AF_INET, &addr->sin_addr, ip, sizeof(ip));
  1126. if ((conversion != NULL) && (strcmp(ip, iface) == 0))
  1127. {
  1128. // IP match
  1129. struct sockaddr_in nativeAddr4 = *addr;
  1130. nativeAddr4.sin_port = htons(port);
  1131. addr4 = [NSData dataWithBytes:&nativeAddr4 length:sizeof(nativeAddr4)];
  1132. }
  1133. }
  1134. }
  1135. else if ((addr6 == nil) && (cursor->ifa_addr->sa_family == AF_INET6))
  1136. {
  1137. // IPv6
  1138. struct sockaddr_in6 *addr = (struct sockaddr_in6 *)cursor->ifa_addr;
  1139. if (strcmp(cursor->ifa_name, iface) == 0)
  1140. {
  1141. // Name match
  1142. struct sockaddr_in6 nativeAddr6 = *addr;
  1143. nativeAddr6.sin6_port = htons(port);
  1144. addr6 = [NSData dataWithBytes:&nativeAddr6 length:sizeof(nativeAddr6)];
  1145. }
  1146. else
  1147. {
  1148. char ip[INET6_ADDRSTRLEN];
  1149. const char *conversion;
  1150. conversion = inet_ntop(AF_INET6, &addr->sin6_addr, ip, sizeof(ip));
  1151. if ((conversion != NULL) && (strcmp(ip, iface) == 0))
  1152. {
  1153. // IP match
  1154. struct sockaddr_in6 nativeAddr6 = *addr;
  1155. nativeAddr6.sin6_port = htons(port);
  1156. addr6 = [NSData dataWithBytes:&nativeAddr6 length:sizeof(nativeAddr6)];
  1157. }
  1158. }
  1159. }
  1160. cursor = cursor->ifa_next;
  1161. }
  1162. freeifaddrs(addrs);
  1163. }
  1164. }
  1165. if (interfaceAddr4Ptr) *interfaceAddr4Ptr = addr4;
  1166. if (interfaceAddr6Ptr) *interfaceAddr6Ptr = addr6;
  1167. }
  1168. /**
  1169. * Converts a numeric hostname into its corresponding address.
  1170. * The hostname is expected to be an IPv4 or IPv6 address represented as a human-readable string. (e.g. 192.168.4.34)
  1171. **/
  1172. - (void)convertNumericHost:(NSString *)numericHost
  1173. port:(uint16_t)port
  1174. intoAddress4:(NSData **)addr4Ptr
  1175. address6:(NSData **)addr6Ptr
  1176. {
  1177. NSData *addr4 = nil;
  1178. NSData *addr6 = nil;
  1179. if (numericHost)
  1180. {
  1181. NSString *portStr = [NSString stringWithFormat:@"%hu", port];
  1182. struct addrinfo hints, *res, *res0;
  1183. memset(&hints, 0, sizeof(hints));
  1184. hints.ai_family = PF_UNSPEC;
  1185. hints.ai_socktype = SOCK_DGRAM;
  1186. hints.ai_protocol = IPPROTO_UDP;
  1187. hints.ai_flags = AI_NUMERICHOST; // No name resolution should be attempted
  1188. if (getaddrinfo([numericHost UTF8String], [portStr UTF8String], &hints, &res0) == 0)
  1189. {
  1190. for (res = res0; res; res = res->ai_next)
  1191. {
  1192. if ((addr4 == nil) && (res->ai_family == AF_INET))
  1193. {
  1194. // Found IPv4 address
  1195. // Wrap the native address structure
  1196. addr4 = [NSData dataWithBytes:res->ai_addr length:res->ai_addrlen];
  1197. }
  1198. else if ((addr6 == nil) && (res->ai_family == AF_INET6))
  1199. {
  1200. // Found IPv6 address
  1201. // Wrap the native address structure
  1202. addr6 = [NSData dataWithBytes:res->ai_addr length:res->ai_addrlen];
  1203. }
  1204. }
  1205. freeaddrinfo(res0);
  1206. }
  1207. }
  1208. if (addr4Ptr) *addr4Ptr = addr4;
  1209. if (addr6Ptr) *addr6Ptr = addr6;
  1210. }
  1211. - (BOOL)isConnectedToAddress4:(NSData *)someAddr4
  1212. {
  1213. NSAssert(dispatch_get_current_queue() == socketQueue, @"Must be dispatched on socketQueue");
  1214. NSAssert(flags & kDidConnect, @"Not connected");
  1215. NSAssert(cachedConnectedAddress, @"Expected cached connected address");
  1216. if (cachedConnectedFamily != AF_INET)
  1217. {
  1218. return NO;
  1219. }
  1220. const struct sockaddr_in *sSockaddr4 = (struct sockaddr_in *)[someAddr4 bytes];
  1221. const struct sockaddr_in *cSockaddr4 = (struct sockaddr_in *)[cachedConnectedAddress bytes];
  1222. if (memcmp(&sSockaddr4->sin_addr, &cSockaddr4->sin_addr, sizeof(struct in_addr)) != 0)
  1223. {
  1224. return NO;
  1225. }
  1226. if (memcmp(&sSockaddr4->sin_port, &cSockaddr4->sin_port, sizeof(in_port_t)) != 0)
  1227. {
  1228. return NO;
  1229. }
  1230. return YES;
  1231. }
  1232. - (BOOL)isConnectedToAddress6:(NSData *)someAddr6
  1233. {
  1234. NSAssert(dispatch_get_current_queue() == socketQueue, @"Must be dispatched on socketQueue");
  1235. NSAssert(flags & kDidConnect, @"Not connected");
  1236. NSAssert(cachedConnectedAddress, @"Expected cached connected address");
  1237. if (cachedConnectedFamily != AF_INET6)
  1238. {
  1239. return NO;
  1240. }
  1241. const struct sockaddr_in6 *sSockaddr6 = (struct sockaddr_in6 *)[someAddr6 bytes];
  1242. const struct sockaddr_in6 *cSockaddr6 = (struct sockaddr_in6 *)[cachedConnectedAddress bytes];
  1243. if (memcmp(&sSockaddr6->sin6_addr, &cSockaddr6->sin6_addr, sizeof(struct in6_addr)) != 0)
  1244. {
  1245. return NO;
  1246. }
  1247. if (memcmp(&sSockaddr6->sin6_port, &cSockaddr6->sin6_port, sizeof(in_port_t)) != 0)
  1248. {
  1249. return NO;
  1250. }
  1251. return YES;
  1252. }
  1253. - (unsigned int)indexOfInterfaceAddr4:(NSData *)interfaceAddr4
  1254. {
  1255. if (interfaceAddr4 == nil)
  1256. return 0;
  1257. if ([interfaceAddr4 length] != sizeof(struct sockaddr_in))
  1258. return 0;
  1259. int result = 0;
  1260. struct sockaddr_in *ifaceAddr = (struct sockaddr_in *)[interfaceAddr4 bytes];
  1261. struct ifaddrs *addrs;
  1262. const struct ifaddrs *cursor;
  1263. if ((getifaddrs(&addrs) == 0))
  1264. {
  1265. cursor = addrs;
  1266. while (cursor != NULL)
  1267. {
  1268. if (cursor->ifa_addr->sa_family == AF_INET)
  1269. {
  1270. // IPv4
  1271. struct sockaddr_in *addr = (struct sockaddr_in *)cursor->ifa_addr;
  1272. if (memcmp(&addr->sin_addr, &ifaceAddr->sin_addr, sizeof(struct in_addr)) == 0)
  1273. {
  1274. result = if_nametoindex(cursor->ifa_name);
  1275. break;
  1276. }
  1277. }
  1278. cursor = cursor->ifa_next;
  1279. }
  1280. freeifaddrs(addrs);
  1281. }
  1282. return result;
  1283. }
  1284. - (unsigned int)indexOfInterfaceAddr6:(NSData *)interfaceAddr6
  1285. {
  1286. if (interfaceAddr6 == nil)
  1287. return 0;
  1288. if ([interfaceAddr6 length] != sizeof(struct sockaddr_in6))
  1289. return 0;
  1290. int result = 0;
  1291. struct sockaddr_in6 *ifaceAddr = (struct sockaddr_in6 *)[interfaceAddr6 bytes];
  1292. struct ifaddrs *addrs;
  1293. const struct ifaddrs *cursor;
  1294. if ((getifaddrs(&addrs) == 0))
  1295. {
  1296. cursor = addrs;
  1297. while (cursor != NULL)
  1298. {
  1299. if (cursor->ifa_addr->sa_family == AF_INET6)
  1300. {
  1301. // IPv6
  1302. struct sockaddr_in6 *addr = (struct sockaddr_in6 *)cursor->ifa_addr;
  1303. if (memcmp(&addr->sin6_addr, &ifaceAddr->sin6_addr, sizeof(struct in6_addr)) == 0)
  1304. {
  1305. result = if_nametoindex(cursor->ifa_name);
  1306. break;
  1307. }
  1308. }
  1309. cursor = cursor->ifa_next;
  1310. }
  1311. freeifaddrs(addrs);
  1312. }
  1313. return result;
  1314. }
  1315. - (void)setupSendAndReceiveSourcesForSocket4
  1316. {
  1317. LogTrace();
  1318. NSAssert(dispatch_get_current_queue() == socketQueue, @"Must be dispatched on socketQueue");
  1319. send4Source = dispatch_source_create(DISPATCH_SOURCE_TYPE_WRITE, socket4FD, 0, socketQueue);
  1320. receive4Source = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, socket4FD, 0, socketQueue);
  1321. // Setup event handlers
  1322. dispatch_source_set_event_handler(send4Source, ^{ @autoreleasepool {
  1323. LogVerbose(@"send4EventBlock");
  1324. LogVerbose(@"dispatch_source_get_data(send4Source) = %lu", dispatch_source_get_data(send4Source));
  1325. flags |= kSock4CanAcceptBytes;
  1326. // If we're ready to send data, do so immediately.
  1327. // Otherwise pause the send source or it will continue to fire over and over again.
  1328. if (currentSend == nil)
  1329. {
  1330. LogVerbose(@"Nothing to send");
  1331. [self suspendSend4Source];
  1332. }
  1333. else if (currentSend->resolveInProgress)
  1334. {
  1335. LogVerbose(@"currentSend - waiting for address resolve");
  1336. [self suspendSend4Source];
  1337. }
  1338. else if (currentSend->filterInProgress)
  1339. {
  1340. LogVerbose(@"currentSend - waiting on sendFilter");
  1341. [self suspendSend4Source];
  1342. }
  1343. else
  1344. {
  1345. [self doSend];
  1346. }
  1347. }});
  1348. dispatch_source_set_event_handler(receive4Source, ^{ @autoreleasepool {
  1349. LogVerbose(@"receive4EventBlock");
  1350. socket4FDBytesAvailable = dispatch_source_get_data(receive4Source);
  1351. LogVerbose(@"socket4FDBytesAvailable: %lu", socket4FDBytesAvailable);
  1352. if (socket4FDBytesAvailable > 0)
  1353. [self doReceive];
  1354. else
  1355. [self doReceiveEOF];
  1356. }});
  1357. // Setup cancel handlers
  1358. __block int socketFDRefCount = 2;
  1359. int theSocketFD = socket4FD;
  1360. #if NEEDS_DISPATCH_RETAIN_RELEASE
  1361. dispatch_source_t theSendSource = send4Source;
  1362. dispatch_source_t theReceiveSource = receive4Source;
  1363. #endif
  1364. dispatch_source_set_cancel_handler(send4Source, ^{
  1365. LogVerbose(@"send4CancelBlock");
  1366. #if NEEDS_DISPATCH_RETAIN_RELEASE
  1367. LogVerbose(@"dispatch_release(send4Source)");
  1368. dispatch_release(theSendSource);
  1369. #endif
  1370. if (--socketFDRefCount == 0)
  1371. {
  1372. LogVerbose(@"close(socket4FD)");
  1373. close(theSocketFD);
  1374. }
  1375. });
  1376. dispatch_source_set_cancel_handler(receive4Source, ^{
  1377. LogVerbose(@"receive4CancelBlock");
  1378. #if NEEDS_DISPATCH_RETAIN_RELEASE
  1379. LogVerbose(@"dispatch_release(receive4Source)");
  1380. dispatch_release(theReceiveSource);
  1381. #endif
  1382. if (--socketFDRefCount == 0)
  1383. {
  1384. LogVerbose(@"close(socket4FD)");
  1385. close(theSocketFD);
  1386. }
  1387. });
  1388. // We will not be able to receive until the socket is bound to a port,
  1389. // either explicitly via bind, or implicitly by connect or by sending data.
  1390. //
  1391. // But we should be able to send immediately.
  1392. socket4FDBytesAvailable = 0;
  1393. flags |= kSock4CanAcceptBytes;
  1394. flags |= kSend4SourceSuspended;
  1395. flags |= kReceive4SourceSuspended;
  1396. }
  1397. - (void)setupSendAndReceiveSourcesForSocket6
  1398. {
  1399. LogTrace();
  1400. NSAssert(dispatch_get_current_queue() == socketQueue, @"Must be dispatched on socketQueue");
  1401. send6Source = dispatch_source_create(DISPATCH_SOURCE_TYPE_WRITE, socket6FD, 0, socketQueue);
  1402. receive6Source = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, socket6FD, 0, socketQueue);
  1403. // Setup event handlers
  1404. dispatch_source_set_event_handler(send6Source, ^{ @autoreleasepool {
  1405. LogVerbose(@"send6EventBlock");
  1406. LogVerbose(@"dispatch_source_get_data(send6Source) = %lu", dispatch_source_get_data(send6Source));
  1407. flags |= kSock6CanAcceptBytes;
  1408. // If we're ready to send data, do so immediately.
  1409. // Otherwise pause the send source or it will continue to fire over and over again.
  1410. if (currentSend == nil)
  1411. {
  1412. LogVerbose(@"Nothing to send");
  1413. [self suspendSend6Source];
  1414. }
  1415. else if (currentSend->resolveInProgress)
  1416. {
  1417. LogVerbose(@"currentSend - waiting for address resolve");
  1418. [self suspendSend6Source];
  1419. }
  1420. else if (currentSend->filterInProgress)
  1421. {
  1422. LogVerbose(@"currentSend - waiting on sendFilter");
  1423. [self suspendSend6Source];
  1424. }
  1425. else
  1426. {
  1427. [self doSend];
  1428. }
  1429. }});
  1430. dispatch_source_set_event_handler(receive6Source, ^{ @autoreleasepool {
  1431. LogVerbose(@"receive6EventBlock");
  1432. socket6FDBytesAvailable = dispatch_source_get_data(receive6Source);
  1433. LogVerbose(@"socket6FDBytesAvailable: %lu", socket6FDBytesAvailable);
  1434. if (socket6FDBytesAvailable > 0)
  1435. [self doReceive];
  1436. else
  1437. [self doReceiveEOF];
  1438. }});
  1439. // Setup cancel handlers
  1440. __block int socketFDRefCount = 2;
  1441. int theSocketFD = socket6FD;
  1442. #if NEEDS_DISPATCH_RETAIN_RELEASE
  1443. dispatch_source_t theSendSource = send6Source;
  1444. dispatch_source_t theReceiveSource = receive6Source;
  1445. #endif
  1446. dispatch_source_set_cancel_handler(send6Source, ^{
  1447. LogVerbose(@"send6CancelBlock");
  1448. #if NEEDS_DISPATCH_RETAIN_RELEASE
  1449. LogVerbose(@"dispatch_release(send6Source)");
  1450. dispatch_release(theSendSource);
  1451. #endif
  1452. if (--socketFDRefCount == 0)
  1453. {
  1454. LogVerbose(@"close(socket6FD)");
  1455. close(theSocketFD);
  1456. }
  1457. });
  1458. dispatch_source_set_cancel_handler(receive6Source, ^{
  1459. LogVerbose(@"receive6CancelBlock");
  1460. #if NEEDS_DISPATCH_RETAIN_RELEASE
  1461. LogVerbose(@"dispatch_release(receive6Source)");
  1462. dispatch_release(theReceiveSource);
  1463. #endif
  1464. if (--socketFDRefCount == 0)
  1465. {
  1466. LogVerbose(@"close(socket6FD)");
  1467. close(theSocketFD);
  1468. }
  1469. });
  1470. // We will not be able to receive until the socket is bound to a port,
  1471. // either explicitly via bind, or implicitly by connect or by sending data.
  1472. //
  1473. // But we should be able to send immediately.
  1474. socket6FDBytesAvailable = 0;
  1475. flags |= kSock6CanAcceptBytes;
  1476. flags |= kSend6SourceSuspended;
  1477. flags |= kReceive6SourceSuspended;
  1478. }
  1479. - (BOOL)createSocket4:(BOOL)useIPv4 socket6:(BOOL)useIPv6 error:(NSError **)errPtr
  1480. {
  1481. LogTrace();
  1482. NSAssert(dispatch_get_current_queue() == socketQueue, @"Must be dispatched on socketQueue");
  1483. NSAssert(((flags & kDidCreateSockets) == 0), @"Sockets have already been created");
  1484. // CreateSocket Block
  1485. // This block will be invoked below.
  1486. int(^createSocket)(int) = ^