Subversion Repositories Mobile Apps.GyroMouse

Rev

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

  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.  
  11. #import "GCDAsyncUdpSocket.h"
  12.  
  13. #if ! __has_feature(objc_arc)
  14. #warning This file must be compiled with ARC. Use -fobjc-arc flag (or convert project to ARC).
  15. // For more information see: https://github.com/robbiehanson/CocoaAsyncSocket/wiki/ARC
  16. #endif
  17.  
  18. #if TARGET_OS_IPHONE
  19.   #import <CFNetwork/CFNetwork.h>
  20.   #import <UIKit/UIKit.h>
  21. #endif
  22.  
  23. #import <arpa/inet.h>
  24. #import <fcntl.h>
  25. #import <ifaddrs.h>
  26. #import <netdb.h>
  27. #import <net/if.h>
  28. #import <sys/socket.h>
  29. #import <sys/types.h>
  30.  
  31.  
  32. #if 0
  33.  
  34. // Logging Enabled - See log level below
  35.  
  36. // Logging uses the CocoaLumberjack framework (which is also GCD based).
  37. // https://github.com/robbiehanson/CocoaLumberjack
  38. //
  39. // It allows us to do a lot of logging without significantly slowing down the code.
  40. #import "DDLog.h"
  41.  
  42. #define LogAsync   NO
  43. #define LogContext 65535
  44.  
  45. #define LogObjc(flg, frmt, ...) LOG_OBJC_MAYBE(LogAsync, logLevel, flg, LogContext, frmt, ##__VA_ARGS__)
  46. #define LogC(flg, frmt, ...)    LOG_C_MAYBE(LogAsync, logLevel, flg, LogContext, frmt, ##__VA_ARGS__)
  47.  
  48. #define LogError(frmt, ...)     LogObjc(LOG_FLAG_ERROR,   (@"%@: " frmt), THIS_FILE, ##__VA_ARGS__)
  49. #define LogWarn(frmt, ...)      LogObjc(LOG_FLAG_WARN,    (@"%@: " frmt), THIS_FILE, ##__VA_ARGS__)
  50. #define LogInfo(frmt, ...)      LogObjc(LOG_FLAG_INFO,    (@"%@: " frmt), THIS_FILE, ##__VA_ARGS__)
  51. #define LogVerbose(frmt, ...)   LogObjc(LOG_FLAG_VERBOSE, (@"%@: " frmt), THIS_FILE, ##__VA_ARGS__)
  52.  
  53. #define LogCError(frmt, ...)    LogC(LOG_FLAG_ERROR,   (@"%@: " frmt), THIS_FILE, ##__VA_ARGS__)
  54. #define LogCWarn(frmt, ...)     LogC(LOG_FLAG_WARN,    (@"%@: " frmt), THIS_FILE, ##__VA_ARGS__)
  55. #define LogCInfo(frmt, ...)     LogC(LOG_FLAG_INFO,    (@"%@: " frmt), THIS_FILE, ##__VA_ARGS__)
  56. #define LogCVerbose(frmt, ...)  LogC(LOG_FLAG_VERBOSE, (@"%@: " frmt), THIS_FILE, ##__VA_ARGS__)
  57.  
  58. #define LogTrace()              LogObjc(LOG_FLAG_VERBOSE, @"%@: %@", THIS_FILE, THIS_METHOD)
  59. #define LogCTrace()             LogC(LOG_FLAG_VERBOSE, @"%@: %s", THIS_FILE, __FUNCTION__)
  60.  
  61. // Log levels : off, error, warn, info, verbose
  62. static const int logLevel = LOG_LEVEL_VERBOSE;
  63.  
  64. #else
  65.  
  66. // Logging Disabled
  67.  
  68. #define LogError(frmt, ...)     {}
  69. #define LogWarn(frmt, ...)      {}
  70. #define LogInfo(frmt, ...)      {}
  71. #define LogVerbose(frmt, ...)   {}
  72.  
  73. #define LogCError(frmt, ...)    {}
  74. #define LogCWarn(frmt, ...)     {}
  75. #define LogCInfo(frmt, ...)     {}
  76. #define LogCVerbose(frmt, ...)  {}
  77.  
  78. #define LogTrace()              {}
  79. #define LogCTrace(frmt, ...)    {}
  80.  
  81. #endif
  82.  
  83. /**
  84.  * Seeing a return statements within an inner block
  85.  * can sometimes be mistaken for a return point of the enclosing method.
  86.  * This makes inline blocks a bit easier to read.
  87. **/
  88. #define return_from_block  return
  89.  
  90. /**
  91.  * A socket file descriptor is really just an integer.
  92.  * It represents the index of the socket within the kernel.
  93.  * This makes invalid file descriptor comparisons easier to read.
  94. **/
  95. #define SOCKET_NULL -1
  96.  
  97. /**
  98.  * Just to type less code.
  99. **/
  100. #define AutoreleasedBlock(block) ^{ @autoreleasepool { block(); }}
  101.  
  102.  
  103. @class GCDAsyncUdpSendPacket;
  104.  
  105. NSString *const GCDAsyncUdpSocketException = @"GCDAsyncUdpSocketException";
  106. NSString *const GCDAsyncUdpSocketErrorDomain = @"GCDAsyncUdpSocketErrorDomain";
  107.  
  108. NSString *const GCDAsyncUdpSocketQueueName = @"GCDAsyncUdpSocket";
  109. NSString *const GCDAsyncUdpSocketThreadName = @"GCDAsyncUdpSocket-CFStream";
  110.  
  111. enum GCDAsyncUdpSocketFlags
  112. {
  113.         kDidCreateSockets        = 1 <<  0,  // If set, the sockets have been created.
  114.         kDidBind                 = 1 <<  1,  // If set, bind has been called.
  115.         kConnecting              = 1 <<  2,  // If set, a connection attempt is in progress.
  116.         kDidConnect              = 1 <<  3,  // If set, socket is connected.
  117.         kReceiveOnce             = 1 <<  4,  // If set, one-at-a-time receive is enabled
  118.         kReceiveContinuous       = 1 <<  5,  // If set, continuous receive is enabled
  119.         kIPv4Deactivated         = 1 <<  6,  // If set, socket4 was closed due to bind or connect on IPv6.
  120.         kIPv6Deactivated         = 1 <<  7,  // If set, socket6 was closed due to bind or connect on IPv4.
  121.         kSend4SourceSuspended    = 1 <<  8,  // If set, send4Source is suspended.
  122.         kSend6SourceSuspended    = 1 <<  9,  // If set, send6Source is suspended.
  123.         kReceive4SourceSuspended = 1 << 10,  // If set, receive4Source is suspended.
  124.         kReceive6SourceSuspended = 1 << 11,  // If set, receive6Source is suspended.
  125.         kSock4CanAcceptBytes     = 1 << 12,  // If set, we know socket4 can accept bytes. If unset, it's unknown.
  126.         kSock6CanAcceptBytes     = 1 << 13,  // If set, we know socket6 can accept bytes. If unset, it's unknown.
  127.         kForbidSendReceive       = 1 << 14,  // If set, no new send or receive operations are allowed to be queued.
  128.         kCloseAfterSends         = 1 << 15,  // If set, close as soon as no more sends are queued.
  129.         kFlipFlop                = 1 << 16,  // Used to alternate between IPv4 and IPv6 sockets.
  130. #if TARGET_OS_IPHONE
  131.         kAddedStreamListener     = 1 << 17,  // If set, CFStreams have been added to listener thread
  132. #endif
  133. };
  134.  
  135. enum GCDAsyncUdpSocketConfig
  136. {
  137.         kIPv4Disabled  = 1 << 0,  // If set, IPv4 is disabled
  138.         kIPv6Disabled  = 1 << 1,  // If set, IPv6 is disabled
  139.         kPreferIPv4    = 1 << 2,  // If set, IPv4 is preferred over IPv6
  140.         kPreferIPv6    = 1 << 3,  // If set, IPv6 is preferred over IPv4
  141. };
  142.  
  143. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  144. #pragma mark -
  145. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  146.  
  147. @interface GCDAsyncUdpSocket ()
  148. {
  149. #if __has_feature(objc_arc_weak)
  150.         __weak id delegate;
  151. #else
  152.         __unsafe_unretained id delegate;
  153. #endif
  154.         dispatch_queue_t delegateQueue;
  155.        
  156.         GCDAsyncUdpSocketReceiveFilterBlock receiveFilterBlock;
  157.         dispatch_queue_t receiveFilterQueue;
  158.         BOOL receiveFilterAsync;
  159.        
  160.         GCDAsyncUdpSocketSendFilterBlock sendFilterBlock;
  161.         dispatch_queue_t sendFilterQueue;
  162.         BOOL sendFilterAsync;
  163.        
  164.         uint32_t flags;
  165.         uint16_t config;
  166.        
  167.         uint16_t max4ReceiveSize;
  168.         uint32_t max6ReceiveSize;
  169.    
  170.     uint16_t maxSendSize;
  171.        
  172.         int socket4FD;
  173.         int socket6FD;
  174.        
  175.         dispatch_queue_t socketQueue;
  176.        
  177.         dispatch_source_t send4Source;
  178.         dispatch_source_t send6Source;
  179.         dispatch_source_t receive4Source;
  180.         dispatch_source_t receive6Source;
  181.         dispatch_source_t sendTimer;
  182.        
  183.         GCDAsyncUdpSendPacket *currentSend;
  184.         NSMutableArray *sendQueue;
  185.        
  186.         unsigned long socket4FDBytesAvailable;
  187.         unsigned long socket6FDBytesAvailable;
  188.        
  189.         uint32_t pendingFilterOperations;
  190.        
  191.         NSData   *cachedLocalAddress4;
  192.         NSString *cachedLocalHost4;
  193.         uint16_t  cachedLocalPort4;
  194.        
  195.         NSData   *cachedLocalAddress6;
  196.         NSString *cachedLocalHost6;
  197.         uint16_t  cachedLocalPort6;
  198.        
  199.         NSData   *cachedConnectedAddress;
  200.         NSString *cachedConnectedHost;
  201.         uint16_t  cachedConnectedPort;
  202.         int       cachedConnectedFamily;
  203.  
  204.         void *IsOnSocketQueueOrTargetQueueKey;    
  205.        
  206. #if TARGET_OS_IPHONE
  207.         CFStreamClientContext streamContext;
  208.         CFReadStreamRef readStream4;
  209.         CFReadStreamRef readStream6;
  210.         CFWriteStreamRef writeStream4;
  211.         CFWriteStreamRef writeStream6;
  212. #endif
  213.        
  214.         id userData;
  215. }
  216.  
  217. - (void)resumeSend4Source;
  218. - (void)resumeSend6Source;
  219. - (void)resumeReceive4Source;
  220. - (void)resumeReceive6Source;
  221. - (void)closeSockets;
  222.  
  223. - (void)maybeConnect;
  224. - (BOOL)connectWithAddress4:(NSData *)address4 error:(NSError **)errPtr;
  225. - (BOOL)connectWithAddress6:(NSData *)address6 error:(NSError **)errPtr;
  226.  
  227. - (void)maybeDequeueSend;
  228. - (void)doPreSend;
  229. - (void)doSend;
  230. - (void)endCurrentSend;
  231. - (void)setupSendTimerWithTimeout:(NSTimeInterval)timeout;
  232.  
  233. - (void)doReceive;
  234. - (void)doReceiveEOF;
  235.  
  236. - (void)closeWithError:(NSError *)error;
  237.  
  238. - (BOOL)performMulticastRequest:(int)requestType forGroup:(NSString *)group onInterface:(NSString *)interface error:(NSError **)errPtr;
  239.  
  240. #if TARGET_OS_IPHONE
  241. - (BOOL)createReadAndWriteStreams:(NSError **)errPtr;
  242. - (BOOL)registerForStreamCallbacks:(NSError **)errPtr;
  243. - (BOOL)addStreamsToRunLoop:(NSError **)errPtr;
  244. - (BOOL)openStreams:(NSError **)errPtr;
  245. - (void)removeStreamsFromRunLoop;
  246. - (void)closeReadAndWriteStreams;
  247. #endif
  248.  
  249. + (NSString *)hostFromSockaddr4:(const struct sockaddr_in *)pSockaddr4;
  250. + (NSString *)hostFromSockaddr6:(const struct sockaddr_in6 *)pSockaddr6;
  251. + (uint16_t)portFromSockaddr4:(const struct sockaddr_in *)pSockaddr4;
  252. + (uint16_t)portFromSockaddr6:(const struct sockaddr_in6 *)pSockaddr6;
  253.  
  254. #if TARGET_OS_IPHONE
  255. // Forward declaration
  256. + (void)listenerThread:(id)unused;
  257. #endif
  258.  
  259. @end
  260.  
  261. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  262. #pragma mark -
  263. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  264.  
  265. /**
  266.  * The GCDAsyncUdpSendPacket encompasses the instructions for a single send/write.
  267. **/
  268. @interface GCDAsyncUdpSendPacket : NSObject {
  269. @public
  270.         NSData *buffer;
  271.         NSTimeInterval timeout;
  272.         long tag;
  273.        
  274.         BOOL resolveInProgress;
  275.         BOOL filterInProgress;
  276.        
  277.         NSArray *resolvedAddresses;
  278.         NSError *resolveError;
  279.        
  280.         NSData *address;
  281.         int addressFamily;
  282. }
  283.  
  284. - (instancetype)initWithData:(NSData *)d timeout:(NSTimeInterval)t tag:(long)i NS_DESIGNATED_INITIALIZER;
  285.  
  286. @end
  287.  
  288. @implementation GCDAsyncUdpSendPacket
  289.  
  290. // Cover the superclass' designated initializer
  291. - (instancetype)init NS_UNAVAILABLE
  292. {
  293.         NSAssert(0, @"Use the designated initializer");
  294.         return nil;
  295. }
  296.  
  297. - (instancetype)initWithData:(NSData *)d timeout:(NSTimeInterval)t tag:(long)i
  298. {
  299.         if ((self = [super init]))
  300.         {
  301.                 buffer = d;
  302.                 timeout = t;
  303.                 tag = i;
  304.                
  305.                 resolveInProgress = NO;
  306.         }
  307.         return self;
  308. }
  309.  
  310.  
  311. @end
  312.  
  313. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  314. #pragma mark -
  315. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  316.  
  317. @interface GCDAsyncUdpSpecialPacket : NSObject {
  318. @public
  319. //      uint8_t type;
  320.        
  321.         BOOL resolveInProgress;
  322.        
  323.         NSArray *addresses;
  324.         NSError *error;
  325. }
  326.  
  327. - (instancetype)init NS_DESIGNATED_INITIALIZER;
  328.  
  329. @end
  330.  
  331. @implementation GCDAsyncUdpSpecialPacket
  332.  
  333. - (instancetype)init
  334. {
  335.         self = [super init];
  336.         return self;
  337. }
  338.  
  339.  
  340. @end
  341.  
  342. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  343. #pragma mark -
  344. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  345.  
  346. @implementation GCDAsyncUdpSocket
  347.  
  348. - (instancetype)init
  349. {
  350.         LogTrace();
  351.        
  352.         return [self initWithDelegate:nil delegateQueue:NULL socketQueue:NULL];
  353. }
  354.  
  355. - (instancetype)initWithSocketQueue:(dispatch_queue_t)sq
  356. {
  357.         LogTrace();
  358.        
  359.         return [self initWithDelegate:nil delegateQueue:NULL socketQueue:sq];
  360. }
  361.  
  362. - (instancetype)initWithDelegate:(id<GCDAsyncUdpSocketDelegate>)aDelegate delegateQueue:(dispatch_queue_t)dq
  363. {
  364.         LogTrace();
  365.        
  366.         return [self initWithDelegate:aDelegate delegateQueue:dq socketQueue:NULL];
  367. }
  368.  
  369. - (instancetype)initWithDelegate:(id<GCDAsyncUdpSocketDelegate>)aDelegate delegateQueue:(dispatch_queue_t)dq socketQueue:(dispatch_queue_t)sq
  370. {
  371.         LogTrace();
  372.        
  373.         if ((self = [super init]))
  374.         {
  375.                 delegate = aDelegate;
  376.                
  377.                 if (dq)
  378.                 {
  379.                         delegateQueue = dq;
  380.                         #if !OS_OBJECT_USE_OBJC
  381.                         dispatch_retain(delegateQueue);
  382.                         #endif
  383.                 }
  384.                
  385.                 max4ReceiveSize = 65535;
  386.                 max6ReceiveSize = 65535;
  387.                
  388.         maxSendSize = 65535;
  389.        
  390.                 socket4FD = SOCKET_NULL;
  391.                 socket6FD = SOCKET_NULL;
  392.                
  393.                 if (sq)
  394.                 {
  395.                         NSAssert(sq != dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0),
  396.                                  @"The given socketQueue parameter must not be a concurrent queue.");
  397.                         NSAssert(sq != dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0),
  398.                                  @"The given socketQueue parameter must not be a concurrent queue.");
  399.                         NSAssert(sq != dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),
  400.                                  @"The given socketQueue parameter must not be a concurrent queue.");
  401.                        
  402.                         socketQueue = sq;
  403.                         #if !OS_OBJECT_USE_OBJC
  404.                         dispatch_retain(socketQueue);
  405.                         #endif
  406.                 }
  407.                 else
  408.                 {
  409.                         socketQueue = dispatch_queue_create([GCDAsyncUdpSocketQueueName UTF8String], NULL);
  410.                 }
  411.  
  412.                 // The dispatch_queue_set_specific() and dispatch_get_specific() functions take a "void *key" parameter.
  413.                 // From the documentation:
  414.                 //
  415.                 // > Keys are only compared as pointers and are never dereferenced.
  416.                 // > Thus, you can use a pointer to a static variable for a specific subsystem or
  417.                 // > any other value that allows you to identify the value uniquely.
  418.                 //
  419.                 // We're just going to use the memory address of an ivar.
  420.                 // Specifically an ivar that is explicitly named for our purpose to make the code more readable.
  421.                 //
  422.                 // However, it feels tedious (and less readable) to include the "&" all the time:
  423.                 // dispatch_get_specific(&IsOnSocketQueueOrTargetQueueKey)
  424.                 //
  425.                 // So we're going to make it so it doesn't matter if we use the '&' or not,
  426.                 // by assigning the value of the ivar to the address of the ivar.
  427.                 // Thus: IsOnSocketQueueOrTargetQueueKey == &IsOnSocketQueueOrTargetQueueKey;
  428.  
  429.                 IsOnSocketQueueOrTargetQueueKey = &IsOnSocketQueueOrTargetQueueKey;
  430.  
  431.                 void *nonNullUnusedPointer = (__bridge void *)self;
  432.                 dispatch_queue_set_specific(socketQueue, IsOnSocketQueueOrTargetQueueKey, nonNullUnusedPointer, NULL);
  433.                
  434.                 currentSend = nil;
  435.                 sendQueue = [[NSMutableArray alloc] initWithCapacity:5];
  436.                
  437.                 #if TARGET_OS_IPHONE
  438.                 [[NSNotificationCenter defaultCenter] addObserver:self
  439.                                                          selector:@selector(applicationWillEnterForeground:)
  440.                                                              name:UIApplicationWillEnterForegroundNotification
  441.                                                            object:nil];
  442.                 #endif
  443.         }
  444.         return self;
  445. }
  446.  
  447. - (void)dealloc
  448. {
  449.         LogInfo(@"%@ - %@ (start)", THIS_METHOD, self);
  450.        
  451. #if TARGET_OS_IPHONE
  452.         [[NSNotificationCenter defaultCenter] removeObserver:self];
  453. #endif
  454.        
  455.         if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
  456.         {
  457.                 [self closeWithError:nil];
  458.         }
  459.         else
  460.         {
  461.                 dispatch_sync(socketQueue, ^{
  462.                         [self closeWithError:nil];
  463.                 });
  464.         }
  465.        
  466.         delegate = nil;
  467.         #if !OS_OBJECT_USE_OBJC
  468.         if (delegateQueue) dispatch_release(delegateQueue);
  469.         #endif
  470.         delegateQueue = NULL;
  471.        
  472.         #if !OS_OBJECT_USE_OBJC
  473.         if (socketQueue) dispatch_release(socketQueue);
  474.         #endif
  475.         socketQueue = NULL;
  476.        
  477.         LogInfo(@"%@ - %@ (finish)", THIS_METHOD, self);
  478. }
  479.  
  480. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  481. #pragma mark Configuration
  482. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  483.  
  484. - (id<GCDAsyncUdpSocketDelegate>)delegate
  485. {
  486.         if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
  487.         {
  488.                 return delegate;
  489.         }
  490.         else
  491.         {
  492.                 __block id result = nil;
  493.                
  494.                 dispatch_sync(socketQueue, ^{
  495.             result = self->delegate;
  496.                 });
  497.                
  498.                 return result;
  499.         }
  500. }
  501.  
  502. - (void)setDelegate:(id<GCDAsyncUdpSocketDelegate>)newDelegate synchronously:(BOOL)synchronously
  503. {
  504.         dispatch_block_t block = ^{
  505.         self->delegate = newDelegate;
  506.         };
  507.        
  508.         if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) {
  509.                 block();
  510.         }
  511.         else {
  512.                 if (synchronously)
  513.                         dispatch_sync(socketQueue, block);
  514.                 else
  515.                         dispatch_async(socketQueue, block);
  516.         }
  517. }
  518.  
  519. - (void)setDelegate:(id<GCDAsyncUdpSocketDelegate>)newDelegate
  520. {
  521.         [self setDelegate:newDelegate synchronously:NO];
  522. }
  523.  
  524. - (void)synchronouslySetDelegate:(id<GCDAsyncUdpSocketDelegate>)newDelegate
  525. {
  526.         [self setDelegate:newDelegate synchronously:YES];
  527. }
  528.  
  529. - (dispatch_queue_t)delegateQueue
  530. {
  531.         if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
  532.         {
  533.                 return delegateQueue;
  534.         }
  535.         else
  536.         {
  537.                 __block dispatch_queue_t result = NULL;
  538.                
  539.                 dispatch_sync(socketQueue, ^{
  540.             result = self->delegateQueue;
  541.                 });
  542.                
  543.                 return result;
  544.         }
  545. }
  546.  
  547. - (void)setDelegateQueue:(dispatch_queue_t)newDelegateQueue synchronously:(BOOL)synchronously
  548. {
  549.         dispatch_block_t block = ^{
  550.                
  551.                 #if !OS_OBJECT_USE_OBJC
  552.         if (self->delegateQueue) dispatch_release(self->delegateQueue);
  553.                 if (newDelegateQueue) dispatch_retain(newDelegateQueue);
  554.                 #endif
  555.                
  556.         self->delegateQueue = newDelegateQueue;
  557.         };
  558.        
  559.         if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) {
  560.                 block();
  561.         }
  562.         else {
  563.                 if (synchronously)
  564.                         dispatch_sync(socketQueue, block);
  565.                 else
  566.                         dispatch_async(socketQueue, block);
  567.         }
  568. }
  569.  
  570. - (void)setDelegateQueue:(dispatch_queue_t)newDelegateQueue
  571. {
  572.         [self setDelegateQueue:newDelegateQueue synchronously:NO];
  573. }
  574.  
  575. - (void)synchronouslySetDelegateQueue:(dispatch_queue_t)newDelegateQueue
  576. {
  577.         [self setDelegateQueue:newDelegateQueue synchronously:YES];
  578. }
  579.  
  580. - (void)getDelegate:(id<GCDAsyncUdpSocketDelegate> *)delegatePtr delegateQueue:(dispatch_queue_t *)delegateQueuePtr
  581. {
  582.         if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
  583.         {
  584.                 if (delegatePtr) *delegatePtr = delegate;
  585.                 if (delegateQueuePtr) *delegateQueuePtr = delegateQueue;
  586.         }
  587.         else
  588.         {
  589.                 __block id dPtr = NULL;
  590.                 __block dispatch_queue_t dqPtr = NULL;
  591.                
  592.                 dispatch_sync(socketQueue, ^{
  593.             dPtr = self->delegate;
  594.             dqPtr = self->delegateQueue;
  595.                 });
  596.                
  597.                 if (delegatePtr) *delegatePtr = dPtr;
  598.                 if (delegateQueuePtr) *delegateQueuePtr = dqPtr;
  599.         }
  600. }
  601.  
  602. - (void)setDelegate:(id<GCDAsyncUdpSocketDelegate>)newDelegate delegateQueue:(dispatch_queue_t)newDelegateQueue synchronously:(BOOL)synchronously
  603. {
  604.         dispatch_block_t block = ^{
  605.                
  606.         self->delegate = newDelegate;
  607.                
  608.                 #if !OS_OBJECT_USE_OBJC
  609.         if (self->delegateQueue) dispatch_release(self->delegateQueue);
  610.                 if (newDelegateQueue) dispatch_retain(newDelegateQueue);
  611.                 #endif
  612.                
  613.         self->delegateQueue = newDelegateQueue;
  614.         };
  615.        
  616.         if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) {
  617.                 block();
  618.         }
  619.         else {
  620.                 if (synchronously)
  621.                         dispatch_sync(socketQueue, block);
  622.                 else
  623.                         dispatch_async(socketQueue, block);
  624.         }
  625. }
  626.  
  627. - (void)setDelegate:(id<GCDAsyncUdpSocketDelegate>)newDelegate delegateQueue:(dispatch_queue_t)newDelegateQueue
  628. {
  629.         [self setDelegate:newDelegate delegateQueue:newDelegateQueue synchronously:NO];
  630. }
  631.  
  632. - (void)synchronouslySetDelegate:(id<GCDAsyncUdpSocketDelegate>)newDelegate delegateQueue:(dispatch_queue_t)newDelegateQueue
  633. {
  634.         [self setDelegate:newDelegate delegateQueue:newDelegateQueue synchronously:YES];
  635. }
  636.  
  637. - (BOOL)isIPv4Enabled
  638. {
  639.         // Note: YES means kIPv4Disabled is OFF
  640.        
  641.         __block BOOL result = NO;
  642.        
  643.         dispatch_block_t block = ^{
  644.                
  645.         result = ((self->config & kIPv4Disabled) == 0);
  646.         };
  647.        
  648.         if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
  649.                 block();
  650.         else
  651.                 dispatch_sync(socketQueue, block);
  652.        
  653.         return result;
  654. }
  655.  
  656. - (void)setIPv4Enabled:(BOOL)flag
  657. {
  658.         // Note: YES means kIPv4Disabled is OFF
  659.        
  660.         dispatch_block_t block = ^{
  661.                
  662.                 LogVerbose(@"%@ %@", THIS_METHOD, (flag ? @"YES" : @"NO"));
  663.                
  664.                 if (flag)
  665.             self->config &= ~kIPv4Disabled;
  666.                 else
  667.             self->config |= kIPv4Disabled;
  668.         };
  669.        
  670.         if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
  671.                 block();
  672.         else
  673.                 dispatch_async(socketQueue, block);
  674. }
  675.  
  676. - (BOOL)isIPv6Enabled
  677. {
  678.         // Note: YES means kIPv6Disabled is OFF
  679.        
  680.         __block BOOL result = NO;
  681.        
  682.         dispatch_block_t block = ^{
  683.                
  684.         result = ((self->config & kIPv6Disabled) == 0);
  685.         };
  686.        
  687.         if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
  688.                 block();
  689.         else
  690.                 dispatch_sync(socketQueue, block);
  691.        
  692.         return result;
  693. }
  694.  
  695. - (void)setIPv6Enabled:(BOOL)flag
  696. {
  697.         // Note: YES means kIPv6Disabled is OFF
  698.        
  699.         dispatch_block_t block = ^{
  700.                
  701.                 LogVerbose(@"%@ %@", THIS_METHOD, (flag ? @"YES" : @"NO"));
  702.                
  703.                 if (flag)
  704.             self->config &= ~kIPv6Disabled;
  705.                 else
  706.             self->config |= kIPv6Disabled;
  707.         };
  708.        
  709.         if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
  710.                 block();
  711.         else
  712.                 dispatch_async(socketQueue, block);
  713. }
  714.  
  715. - (BOOL)isIPv4Preferred
  716. {
  717.         __block BOOL result = NO;
  718.        
  719.         dispatch_block_t block = ^{
  720.         result = (self->config & kPreferIPv4) ? YES : NO;
  721.         };
  722.        
  723.         if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
  724.                 block();
  725.         else
  726.                 dispatch_sync(socketQueue, block);
  727.        
  728.         return result;
  729. }
  730.  
  731. - (BOOL)isIPv6Preferred
  732. {
  733.         __block BOOL result = NO;
  734.        
  735.         dispatch_block_t block = ^{
  736.         result = (self->config & kPreferIPv6) ? YES : NO;
  737.         };
  738.        
  739.         if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
  740.                 block();
  741.         else
  742.                 dispatch_sync(socketQueue, block);
  743.        
  744.         return result;
  745. }
  746.  
  747. - (BOOL)isIPVersionNeutral
  748. {
  749.         __block BOOL result = NO;
  750.        
  751.         dispatch_block_t block = ^{
  752.         result = (self->config & (kPreferIPv4 | kPreferIPv6)) == 0;
  753.         };
  754.        
  755.         if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
  756.                 block();
  757.         else
  758.                 dispatch_sync(socketQueue, block);
  759.        
  760.         return result;
  761. }
  762.  
  763. - (void)setPreferIPv4
  764. {
  765.         dispatch_block_t block = ^{
  766.                
  767.                 LogTrace();
  768.                
  769.         self->config |=  kPreferIPv4;
  770.         self->config &= ~kPreferIPv6;
  771.                
  772.         };
  773.        
  774.         if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
  775.                 block();
  776.         else
  777.                 dispatch_async(socketQueue, block);
  778. }
  779.  
  780. - (void)setPreferIPv6
  781. {
  782.         dispatch_block_t block = ^{
  783.                
  784.                 LogTrace();
  785.                
  786.         self->config &= ~kPreferIPv4;
  787.         self->config |=  kPreferIPv6;
  788.                
  789.         };
  790.        
  791.         if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
  792.                 block();
  793.         else
  794.                 dispatch_async(socketQueue, block);
  795. }
  796.  
  797. - (void)setIPVersionNeutral
  798. {
  799.         dispatch_block_t block = ^{
  800.                
  801.                 LogTrace();
  802.                
  803.         self->config &= ~kPreferIPv4;
  804.         self->config &= ~kPreferIPv6;
  805.                
  806.         };
  807.        
  808.         if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
  809.                 block();
  810.         else
  811.                 dispatch_async(socketQueue, block);
  812. }
  813.  
  814. - (uint16_t)maxReceiveIPv4BufferSize
  815. {
  816.         __block uint16_t result = 0;
  817.        
  818.         dispatch_block_t block = ^{
  819.                
  820.         result = self->max4ReceiveSize;
  821.         };
  822.        
  823.         if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
  824.                 block();
  825.         else
  826.                 dispatch_sync(socketQueue, block);
  827.        
  828.         return result;
  829. }
  830.  
  831. - (void)setMaxReceiveIPv4BufferSize:(uint16_t)max
  832. {
  833.         dispatch_block_t block = ^{
  834.                
  835.                 LogVerbose(@"%@ %u", THIS_METHOD, (unsigned)max);
  836.                
  837.         self->max4ReceiveSize = max;
  838.         };
  839.        
  840.         if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
  841.                 block();
  842.         else
  843.                 dispatch_async(socketQueue, block);
  844. }
  845.  
  846. - (uint32_t)maxReceiveIPv6BufferSize
  847. {
  848.         __block uint32_t result = 0;
  849.        
  850.         dispatch_block_t block = ^{
  851.                
  852.         result = self->max6ReceiveSize;
  853.         };
  854.        
  855.         if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
  856.                 block();
  857.         else
  858.                 dispatch_sync(socketQueue, block);
  859.        
  860.         return result;
  861. }
  862.  
  863. - (void)setMaxReceiveIPv6BufferSize:(uint32_t)max
  864. {
  865.         dispatch_block_t block = ^{
  866.                
  867.                 LogVerbose(@"%@ %u", THIS_METHOD, (unsigned)max);
  868.                
  869.         self->max6ReceiveSize = max;
  870.         };
  871.        
  872.         if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
  873.                 block();
  874.         else
  875.                 dispatch_async(socketQueue, block);
  876. }
  877.  
  878. - (void)setMaxSendBufferSize:(uint16_t)max
  879. {
  880.     dispatch_block_t block = ^{
  881.        
  882.         LogVerbose(@"%@ %u", THIS_METHOD, (unsigned)max);
  883.        
  884.         self->maxSendSize = max;
  885.     };
  886.    
  887.     if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
  888.         block();
  889.     else
  890.         dispatch_async(socketQueue, block);
  891. }
  892.  
  893. - (uint16_t)maxSendBufferSize
  894. {
  895.     __block uint16_t result = 0;
  896.    
  897.     dispatch_block_t block = ^{
  898.        
  899.         result = self->maxSendSize;
  900.     };
  901.    
  902.     if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
  903.         block();
  904.     else
  905.         dispatch_sync(socketQueue, block);
  906.    
  907.     return result;
  908. }
  909.  
  910. - (id)userData
  911. {
  912.         __block id result = nil;
  913.        
  914.         dispatch_block_t block = ^{
  915.                
  916.         result = self->userData;
  917.         };
  918.        
  919.         if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
  920.                 block();
  921.         else
  922.                 dispatch_sync(socketQueue, block);
  923.        
  924.         return result;
  925. }
  926.  
  927. - (void)setUserData:(id)arbitraryUserData
  928. {
  929.         dispatch_block_t block = ^{
  930.                
  931.         if (self->userData != arbitraryUserData)
  932.                 {
  933.             self->userData = arbitraryUserData;
  934.                 }
  935.         };
  936.        
  937.         if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
  938.                 block();
  939.         else
  940.                 dispatch_async(socketQueue, block);
  941. }
  942.  
  943. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  944. #pragma mark Delegate Helpers
  945. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  946.  
  947. - (void)notifyDidConnectToAddress:(NSData *)anAddress
  948. {
  949.         LogTrace();
  950.        
  951.         __strong id<GCDAsyncUdpSocketDelegate> theDelegate = delegate;
  952.         if (delegateQueue && [theDelegate respondsToSelector:@selector(udpSocket:didConnectToAddress:)])
  953.         {
  954.                 NSData *address = [anAddress copy]; // In case param is NSMutableData
  955.                
  956.                 dispatch_async(delegateQueue, ^{ @autoreleasepool {
  957.                        
  958.                         [theDelegate udpSocket:self didConnectToAddress:address];
  959.                 }});
  960.         }
  961. }
  962.  
  963. - (void)notifyDidNotConnect:(NSError *)error
  964. {
  965.         LogTrace();
  966.        
  967.         __strong id<GCDAsyncUdpSocketDelegate> theDelegate = delegate;
  968.         if (delegateQueue && [theDelegate respondsToSelector:@selector(udpSocket:didNotConnect:)])
  969.         {
  970.                 dispatch_async(delegateQueue, ^{ @autoreleasepool {
  971.                        
  972.                         [theDelegate udpSocket:self didNotConnect:error];
  973.                 }});
  974.         }
  975. }
  976.  
  977. - (void)notifyDidSendDataWithTag:(long)tag
  978. {
  979.         LogTrace();
  980.        
  981.         __strong id<GCDAsyncUdpSocketDelegate> theDelegate = delegate;
  982.         if (delegateQueue && [theDelegate respondsToSelector:@selector(udpSocket:didSendDataWithTag:)])
  983.         {
  984.                 dispatch_async(delegateQueue, ^{ @autoreleasepool {
  985.                        
  986.                         [theDelegate udpSocket:self didSendDataWithTag:tag];
  987.                 }});
  988.         }
  989. }
  990.  
  991. - (void)notifyDidNotSendDataWithTag:(long)tag dueToError:(NSError *)error
  992. {
  993.         LogTrace();
  994.        
  995.         __strong id<GCDAsyncUdpSocketDelegate> theDelegate = delegate;
  996.         if (delegateQueue && [theDelegate respondsToSelector:@selector(udpSocket:didNotSendDataWithTag:dueToError:)])
  997.         {
  998.                 dispatch_async(delegateQueue, ^{ @autoreleasepool {
  999.                        
  1000.                         [theDelegate udpSocket:self didNotSendDataWithTag:tag dueToError:error];
  1001.                 }});
  1002.         }
  1003. }
  1004.  
  1005. - (void)notifyDidReceiveData:(NSData *)data fromAddress:(NSData *)address withFilterContext:(id)context
  1006. {
  1007.         LogTrace();
  1008.        
  1009.         SEL selector = @selector(udpSocket:didReceiveData:fromAddress:withFilterContext:);
  1010.        
  1011.         __strong id<GCDAsyncUdpSocketDelegate> theDelegate = delegate;
  1012.         if (delegateQueue && [theDelegate respondsToSelector:selector])
  1013.         {
  1014.                 dispatch_async(delegateQueue, ^{ @autoreleasepool {
  1015.                        
  1016.                         [theDelegate udpSocket:self didReceiveData:data fromAddress:address withFilterContext:context];
  1017.                 }});
  1018.         }
  1019. }
  1020.  
  1021. - (void)notifyDidCloseWithError:(NSError *)error
  1022. {
  1023.         LogTrace();
  1024.        
  1025.         __strong id<GCDAsyncUdpSocketDelegate> theDelegate = delegate;
  1026.         if (delegateQueue && [theDelegate respondsToSelector:@selector(udpSocketDidClose:withError:)])
  1027.         {
  1028.                 dispatch_async(delegateQueue, ^{ @autoreleasepool {
  1029.                        
  1030.                         [theDelegate udpSocketDidClose:self withError:error];
  1031.                 }});
  1032.         }
  1033. }
  1034.  
  1035. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1036. #pragma mark Errors
  1037. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1038.  
  1039. - (NSError *)badConfigError:(NSString *)errMsg
  1040. {
  1041.         NSDictionary *userInfo = @{NSLocalizedDescriptionKey : errMsg};
  1042.        
  1043.         return [NSError errorWithDomain:GCDAsyncUdpSocketErrorDomain
  1044.                                    code:GCDAsyncUdpSocketBadConfigError
  1045.                                userInfo:userInfo];
  1046. }
  1047.  
  1048. - (NSError *)badParamError:(NSString *)errMsg
  1049. {
  1050.         NSDictionary *userInfo = @{NSLocalizedDescriptionKey : errMsg};
  1051.        
  1052.         return [NSError errorWithDomain:GCDAsyncUdpSocketErrorDomain
  1053.                                    code:GCDAsyncUdpSocketBadParamError
  1054.                                userInfo:userInfo];
  1055. }
  1056.  
  1057. - (NSError *)gaiError:(int)gai_error
  1058. {
  1059.         NSString *errMsg = [NSString stringWithCString:gai_strerror(gai_error) encoding:NSASCIIStringEncoding];
  1060.         NSDictionary *userInfo = @{NSLocalizedDescriptionKey : errMsg};
  1061.        
  1062.         return [NSError errorWithDomain:@"kCFStreamErrorDomainNetDB" code:gai_error userInfo:userInfo];
  1063. }
  1064.  
  1065. - (NSError *)errnoErrorWithReason:(NSString *)reason
  1066. {
  1067.         NSString *errMsg = [NSString stringWithUTF8String:strerror(errno)];
  1068.         NSDictionary *userInfo;
  1069.        
  1070.         if (reason)
  1071.                 userInfo = @{NSLocalizedDescriptionKey : errMsg,
  1072.                                          NSLocalizedFailureReasonErrorKey : reason};
  1073.         else
  1074.                 userInfo = @{NSLocalizedDescriptionKey : errMsg};
  1075.        
  1076.         return [NSError errorWithDomain:NSPOSIXErrorDomain code:errno userInfo:userInfo];
  1077. }
  1078.  
  1079. - (NSError *)errnoError
  1080. {
  1081.         return [self errnoErrorWithReason:nil];
  1082. }
  1083.  
  1084. /**
  1085.  * Returns a standard send timeout error.
  1086. **/
  1087. - (NSError *)sendTimeoutError
  1088. {
  1089.         NSString *errMsg = NSLocalizedStringWithDefaultValue(@"GCDAsyncUdpSocketSendTimeoutError",
  1090.                                                              @"GCDAsyncUdpSocket", [NSBundle mainBundle],
  1091.                                                              @"Send operation timed out", nil);
  1092.        
  1093.         NSDictionary *userInfo = @{NSLocalizedDescriptionKey : errMsg};
  1094.        
  1095.         return [NSError errorWithDomain:GCDAsyncUdpSocketErrorDomain
  1096.                                    code:GCDAsyncUdpSocketSendTimeoutError
  1097.                                userInfo:userInfo];
  1098. }
  1099.  
  1100. - (NSError *)socketClosedError
  1101. {
  1102.         NSString *errMsg = NSLocalizedStringWithDefaultValue(@"GCDAsyncUdpSocketClosedError",
  1103.                                                              @"GCDAsyncUdpSocket", [NSBundle mainBundle],
  1104.                                                              @"Socket closed", nil);
  1105.        
  1106.         NSDictionary *userInfo = @{NSLocalizedDescriptionKey : errMsg};
  1107.        
  1108.         return [NSError errorWithDomain:GCDAsyncUdpSocketErrorDomain code:GCDAsyncUdpSocketClosedError userInfo:userInfo];
  1109. }
  1110.  
  1111. - (NSError *)otherError:(NSString *)errMsg
  1112. {
  1113.         NSDictionary *userInfo = @{NSLocalizedDescriptionKey : errMsg};
  1114.        
  1115.         return [NSError errorWithDomain:GCDAsyncUdpSocketErrorDomain
  1116.                                    code:GCDAsyncUdpSocketOtherError
  1117.                                userInfo:userInfo];
  1118. }
  1119.  
  1120. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1121. #pragma mark Utilities
  1122. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1123.  
  1124. - (BOOL)preOp:(NSError **)errPtr
  1125. {
  1126.         NSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @"Must be dispatched on socketQueue");
  1127.        
  1128.         if (delegate == nil) // Must have delegate set
  1129.         {
  1130.                 if (errPtr)
  1131.                 {
  1132.                         NSString *msg = @"Attempting to use socket without a delegate. Set a delegate first.";
  1133.                         *errPtr = [self badConfigError:msg];
  1134.                 }
  1135.                 return NO;
  1136.         }
  1137.        
  1138.         if (delegateQueue == NULL) // Must have delegate queue set
  1139.         {
  1140.                 if (errPtr)
  1141.                 {
  1142.                         NSString *msg = @"Attempting to use socket without a delegate queue. Set a delegate queue first.";
  1143.                         *errPtr = [self badConfigError:msg];
  1144.                 }
  1145.                 return NO;
  1146.         }
  1147.        
  1148.         return YES;
  1149. }
  1150.  
  1151. /**
  1152.  * This method executes on a global concurrent queue.
  1153.  * When complete, it executes the given completion block on the socketQueue.
  1154. **/
  1155. - (void)asyncResolveHost:(NSString *)aHost
  1156.                     port:(uint16_t)port
  1157.      withCompletionBlock:(void (^)(NSArray *addresses, NSError *error))completionBlock
  1158. {
  1159.         LogTrace();
  1160.        
  1161.         // Check parameter(s)
  1162.        
  1163.         if (aHost == nil)
  1164.         {
  1165.                 NSString *msg = @"The host param is nil. Should be domain name or IP address string.";
  1166.                 NSError *error = [self badParamError:msg];
  1167.                
  1168.                 // We should still use dispatch_async since this method is expected to be asynchronous
  1169.                
  1170.                 dispatch_async(socketQueue, ^{ @autoreleasepool {
  1171.                        
  1172.                         completionBlock(nil, error);
  1173.                 }});
  1174.                
  1175.                 return;
  1176.         }
  1177.        
  1178.         // It's possible that the given aHost parameter is actually a NSMutableString.
  1179.         // So we want to copy it now, within this block that will be executed synchronously.
  1180.         // This way the asynchronous lookup block below doesn't have to worry about it changing.
  1181.        
  1182.         NSString *host = [aHost copy];
  1183.        
  1184.        
  1185.         dispatch_queue_t globalConcurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
  1186.         dispatch_async(globalConcurrentQueue, ^{ @autoreleasepool {
  1187.                
  1188.                 NSMutableArray *addresses = [NSMutableArray arrayWithCapacity:2];
  1189.                 NSError *error = nil;
  1190.                
  1191.                 if ([host isEqualToString:@"localhost"] || [host isEqualToString:@"loopback"])
  1192.                 {
  1193.                         // Use LOOPBACK address
  1194.                         struct sockaddr_in sockaddr4;
  1195.                         memset(&sockaddr4, 0, sizeof(sockaddr4));
  1196.                        
  1197.                         sockaddr4.sin_len         = sizeof(struct sockaddr_in);
  1198.                         sockaddr4.sin_family      = AF_INET;
  1199.                         sockaddr4.sin_port        = htons(port);
  1200.                         sockaddr4.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
  1201.                        
  1202.                         struct sockaddr_in6 sockaddr6;
  1203.                         memset(&sockaddr6, 0, sizeof(sockaddr6));
  1204.                        
  1205.                         sockaddr6.sin6_len       = sizeof(struct sockaddr_in6);
  1206.                         sockaddr6.sin6_family    = AF_INET6;
  1207.                         sockaddr6.sin6_port      = htons(port);
  1208.                         sockaddr6.sin6_addr      = in6addr_loopback;
  1209.                        
  1210.                         // Wrap the native address structures and add to list
  1211.                         [addresses addObject:[NSData dataWithBytes:&sockaddr4 length:sizeof(sockaddr4)]];
  1212.                         [addresses addObject:[NSData dataWithBytes:&sockaddr6 length:sizeof(sockaddr6)]];
  1213.                 }
  1214.                 else
  1215.                 {
  1216.                         NSString *portStr = [NSString stringWithFormat:@"%hu", port];
  1217.                        
  1218.                         struct addrinfo hints, *res, *res0;
  1219.                        
  1220.                         memset(&hints, 0, sizeof(hints));
  1221.                         hints.ai_family   = PF_UNSPEC;
  1222.                         hints.ai_socktype = SOCK_DGRAM;
  1223.                         hints.ai_protocol = IPPROTO_UDP;
  1224.                        
  1225.                         int gai_error = getaddrinfo([host UTF8String], [portStr UTF8String], &hints, &res0);
  1226.                        
  1227.                         if (gai_error)
  1228.                         {
  1229.                                 error = [self gaiError:gai_error];
  1230.                         }
  1231.                         else
  1232.                         {
  1233.                                 for(res = res0; res; res = res->ai_next)
  1234.                                 {
  1235.                                         if (res->ai_family == AF_INET)
  1236.                                         {
  1237.                                                 // Found IPv4 address
  1238.                                                 // Wrap the native address structure and add to list
  1239.                                                
  1240.                                                 [addresses addObject:[NSData dataWithBytes:res->ai_addr length:res->ai_addrlen]];
  1241.                                         }
  1242.                                         else if (res->ai_family == AF_INET6)
  1243.                                         {
  1244.  
  1245.                         // Fixes connection issues with IPv6, it is the same solution for udp socket.
  1246.                         // https://github.com/robbiehanson/CocoaAsyncSocket/issues/429#issuecomment-222477158
  1247.                         struct sockaddr_in6 *sockaddr = (struct sockaddr_in6 *)(void *)res->ai_addr;
  1248.                         in_port_t *portPtr = &sockaddr->sin6_port;
  1249.                         if ((portPtr != NULL) && (*portPtr == 0)) {
  1250.                             *portPtr = htons(port);
  1251.                         }
  1252.  
  1253.                         // Found IPv6 address
  1254.                         // Wrap the native address structure and add to list
  1255.                                                 [addresses addObject:[NSData dataWithBytes:res->ai_addr length:res->ai_addrlen]];
  1256.                                         }
  1257.                                 }
  1258.                                 freeaddrinfo(res0);
  1259.                                
  1260.                                 if ([addresses count] == 0)
  1261.                                 {
  1262.                                         error = [self gaiError:EAI_FAIL];
  1263.                                 }
  1264.                         }
  1265.                 }
  1266.                
  1267.         dispatch_async(self->socketQueue, ^{ @autoreleasepool {
  1268.                        
  1269.                         completionBlock(addresses, error);
  1270.                 }});
  1271.                
  1272.         }});
  1273. }
  1274.  
  1275. /**
  1276.  * This method picks an address from the given list of addresses.
  1277.  * The address picked depends upon which protocols are disabled, deactived, & preferred.
  1278.  *
  1279.  * Returns the address family (AF_INET or AF_INET6) of the picked address,
  1280.  * or AF_UNSPEC and the corresponding error is there's a problem.
  1281. **/
  1282. - (int)getAddress:(NSData **)addressPtr error:(NSError **)errorPtr fromAddresses:(NSArray *)addresses
  1283. {
  1284.         NSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @"Must be dispatched on socketQueue");
  1285.         NSAssert([addresses count] > 0, @"Expected at least one address");
  1286.        
  1287.         int resultAF = AF_UNSPEC;
  1288.         NSData *resultAddress = nil;
  1289.         NSError *resultError = nil;
  1290.        
  1291.         // Check for problems
  1292.        
  1293.         BOOL resolvedIPv4Address = NO;
  1294.         BOOL resolvedIPv6Address = NO;
  1295.        
  1296.         for (NSData *address in addresses)
  1297.         {
  1298.                 switch ([[self class] familyFromAddress:address])
  1299.                 {
  1300.                         case AF_INET  : resolvedIPv4Address = YES; break;
  1301.                         case AF_INET6 : resolvedIPv6Address = YES; break;
  1302.                        
  1303.                         default       : NSAssert(NO, @"Addresses array contains invalid address");
  1304.                 }
  1305.         }
  1306.        
  1307.         BOOL isIPv4Disabled = (config & kIPv4Disabled) ? YES : NO;
  1308.         BOOL isIPv6Disabled = (config & kIPv6Disabled) ? YES : NO;
  1309.        
  1310.         if (isIPv4Disabled && !resolvedIPv6Address)
  1311.         {
  1312.                 NSString *msg = @"IPv4 has been disabled and DNS lookup found no IPv6 address(es).";
  1313.                 resultError = [self otherError:msg];
  1314.                
  1315.                 if (addressPtr) *addressPtr = resultAddress;
  1316.                 if (errorPtr) *errorPtr = resultError;
  1317.                
  1318.                 return resultAF;
  1319.         }
  1320.        
  1321.         if (isIPv6Disabled && !resolvedIPv4Address)
  1322.         {
  1323.                 NSString *msg = @"IPv6 has been disabled and DNS lookup found no IPv4 address(es).";
  1324.                 resultError = [self otherError:msg];
  1325.                
  1326.                 if (addressPtr) *addressPtr = resultAddress;
  1327.                 if (errorPtr) *errorPtr = resultError;
  1328.                
  1329.                 return resultAF;
  1330.         }
  1331.        
  1332.         BOOL isIPv4Deactivated = (flags & kIPv4Deactivated) ? YES : NO;
  1333.         BOOL isIPv6Deactivated = (flags & kIPv6Deactivated) ? YES : NO;
  1334.        
  1335.         if (isIPv4Deactivated && !resolvedIPv6Address)
  1336.         {
  1337.                 NSString *msg = @"IPv4 has been deactivated due to bind/connect, and DNS lookup found no IPv6 address(es).";
  1338.                 resultError = [self otherError:msg];
  1339.                
  1340.                 if (addressPtr) *addressPtr = resultAddress;
  1341.                 if (errorPtr) *errorPtr = resultError;
  1342.                
  1343.                 return resultAF;
  1344.         }
  1345.        
  1346.         if (isIPv6Deactivated && !resolvedIPv4Address)
  1347.         {
  1348.                 NSString *msg = @"IPv6 has been deactivated due to bind/connect, and DNS lookup found no IPv4 address(es).";
  1349.                 resultError = [self otherError:msg];
  1350.                
  1351.                 if (addressPtr) *addressPtr = resultAddress;
  1352.                 if (errorPtr) *errorPtr = resultError;
  1353.                
  1354.                 return resultAF;
  1355.         }
  1356.        
  1357.         // Extract first IPv4 and IPv6 address in list
  1358.        
  1359.         BOOL ipv4WasFirstInList = YES;
  1360.         NSData *address4 = nil;
  1361.         NSData *address6 = nil;
  1362.        
  1363.         for (NSData *address in addresses)
  1364.         {
  1365.                 int af = [[self class] familyFromAddress:address];
  1366.                
  1367.                 if (af == AF_INET)
  1368.                 {
  1369.                         if (address4 == nil)
  1370.                         {
  1371.                                 address4 = address;
  1372.                                
  1373.                                 if (address6)
  1374.                                         break;
  1375.                                 else
  1376.                                         ipv4WasFirstInList = YES;
  1377.                         }
  1378.                 }
  1379.                 else // af == AF_INET6
  1380.                 {
  1381.                         if (address6 == nil)
  1382.                         {
  1383.                                 address6 = address;
  1384.                                
  1385.                                 if (address4)
  1386.                                         break;
  1387.                                 else
  1388.                                         ipv4WasFirstInList = NO;
  1389.                         }
  1390.                 }
  1391.         }
  1392.        
  1393.         // Determine socket type
  1394.        
  1395.         BOOL preferIPv4 = (config & kPreferIPv4) ? YES : NO;
  1396.         BOOL preferIPv6 = (config & kPreferIPv6) ? YES : NO;
  1397.        
  1398.         BOOL useIPv4 = ((preferIPv4 && address4) || (address6 == nil));
  1399.         BOOL useIPv6 = ((preferIPv6 && address6) || (address4 == nil));
  1400.        
  1401.         NSAssert(!(preferIPv4 && preferIPv6), @"Invalid config state");
  1402.         NSAssert(!(useIPv4 && useIPv6), @"Invalid logic");
  1403.        
  1404.         if (useIPv4 || (!useIPv6 && ipv4WasFirstInList))
  1405.         {
  1406.                 resultAF = AF_INET;
  1407.                 resultAddress = address4;
  1408.         }
  1409.         else
  1410.         {
  1411.                 resultAF = AF_INET6;
  1412.                 resultAddress = address6;
  1413.         }
  1414.        
  1415.         if (addressPtr) *addressPtr = resultAddress;
  1416.         if (errorPtr) *errorPtr = resultError;
  1417.                
  1418.         return resultAF;
  1419. }
  1420.  
  1421. /**
  1422.  * Finds the address(es) of an interface description.
  1423.  * An inteface description may be an interface name (en0, en1, lo0) or corresponding IP (192.168.4.34).
  1424. **/
  1425. - (void)convertIntefaceDescription:(NSString *)interfaceDescription
  1426.                               port:(uint16_t)port
  1427.                       intoAddress4:(NSData **)interfaceAddr4Ptr
  1428.                           address6:(NSData **)interfaceAddr6Ptr
  1429. {
  1430.         NSData *addr4 = nil;
  1431.         NSData *addr6 = nil;
  1432.        
  1433.         if (interfaceDescription == nil)
  1434.         {
  1435.                 // ANY address
  1436.                
  1437.                 struct sockaddr_in sockaddr4;
  1438.                 memset(&sockaddr4, 0, sizeof(sockaddr4));
  1439.                
  1440.                 sockaddr4.sin_len         = sizeof(sockaddr4);
  1441.                 sockaddr4.sin_family      = AF_INET;
  1442.                 sockaddr4.sin_port        = htons(port);
  1443.                 sockaddr4.sin_addr.s_addr = htonl(INADDR_ANY);
  1444.                
  1445.                 struct sockaddr_in6 sockaddr6;
  1446.                 memset(&sockaddr6, 0, sizeof(sockaddr6));
  1447.                
  1448.                 sockaddr6.sin6_len       = sizeof(sockaddr6);
  1449.                 sockaddr6.sin6_family    = AF_INET6;
  1450.                 sockaddr6.sin6_port      = htons(port);
  1451.                 sockaddr6.sin6_addr      = in6addr_any;
  1452.                
  1453.                 addr4 = [NSData dataWithBytes:&sockaddr4 length:sizeof(sockaddr4)];
  1454.                 addr6 = [NSData dataWithBytes:&sockaddr6 length:sizeof(sockaddr6)];
  1455.         }
  1456.         else if ([interfaceDescription isEqualToString:@"localhost"] ||
  1457.                  [interfaceDescription isEqualToString:@"loopback"])
  1458.         {
  1459.                 // LOOPBACK address
  1460.                
  1461.                 struct sockaddr_in sockaddr4;
  1462.                 memset(&sockaddr4, 0, sizeof(sockaddr4));
  1463.                
  1464.                 sockaddr4.sin_len         = sizeof(struct sockaddr_in);
  1465.                 sockaddr4.sin_family      = AF_INET;
  1466.                 sockaddr4.sin_port        = htons(port);
  1467.                 sockaddr4.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
  1468.                
  1469.                 struct sockaddr_in6 sockaddr6;
  1470.                 memset(&sockaddr6, 0, sizeof(sockaddr6));
  1471.                
  1472.                 sockaddr6.sin6_len       = sizeof(struct sockaddr_in6);
  1473.                 sockaddr6.sin6_family    = AF_INET6;
  1474.                 sockaddr6.sin6_port      = htons(port);
  1475.                 sockaddr6.sin6_addr      = in6addr_loopback;
  1476.                
  1477.                 addr4 = [NSData dataWithBytes:&sockaddr4 length:sizeof(sockaddr4)];
  1478.                 addr6 = [NSData dataWithBytes:&sockaddr6 length:sizeof(sockaddr6)];
  1479.         }
  1480.         else
  1481.         {
  1482.                 const char *iface = [interfaceDescription UTF8String];
  1483.                
  1484.                 struct ifaddrs *addrs;
  1485.                 const struct ifaddrs *cursor;
  1486.                
  1487.                 if ((getifaddrs(&addrs) == 0))
  1488.                 {
  1489.                         cursor = addrs;
  1490.                         while (cursor != NULL)
  1491.                         {
  1492.                                 if ((addr4 == nil) && (cursor->ifa_addr->sa_family == AF_INET))
  1493.                                 {
  1494.                                         // IPv4
  1495.                                        
  1496.                                         struct sockaddr_in *addr = (struct sockaddr_in *)(void *)cursor->ifa_addr;
  1497.                                        
  1498.                                         if (strcmp(cursor->ifa_name, iface) == 0)
  1499.                                         {
  1500.                                                 // Name match
  1501.                                                
  1502.                                                 struct sockaddr_in nativeAddr4 = *addr;
  1503.                                                 nativeAddr4.sin_port = htons(port);
  1504.                                                
  1505.                                                 addr4 = [NSData dataWithBytes:&nativeAddr4 length:sizeof(nativeAddr4)];
  1506.                                         }
  1507.                                         else
  1508.                                         {
  1509.                                                 char ip[INET_ADDRSTRLEN];
  1510.                                                
  1511.                                                 const char *conversion;
  1512.                                                 conversion = inet_ntop(AF_INET, &addr->sin_addr, ip, sizeof(ip));
  1513.                                                
  1514.                                                 if ((conversion != NULL) && (strcmp(ip, iface) == 0))
  1515.                                                 {
  1516.                                                         // IP match
  1517.                                                        
  1518.                                                         struct sockaddr_in nativeAddr4 = *addr;
  1519.                                                         nativeAddr4.sin_port = htons(port);
  1520.                                                        
  1521.                                                         addr4 = [NSData dataWithBytes:&nativeAddr4 length:sizeof(nativeAddr4)];
  1522.                                                 }
  1523.                                         }
  1524.                                 }
  1525.                                 else if ((addr6 == nil) && (cursor->ifa_addr->sa_family == AF_INET6))
  1526.                                 {
  1527.                                         // IPv6
  1528.                                        
  1529.                                         const struct sockaddr_in6 *addr = (const struct sockaddr_in6 *)(const void *)cursor->ifa_addr;
  1530.                                        
  1531.                                         if (strcmp(cursor->ifa_name, iface) == 0)
  1532.                                         {
  1533.                                                 // Name match
  1534.                                                
  1535.                                                 struct sockaddr_in6 nativeAddr6 = *addr;
  1536.                                                 nativeAddr6.sin6_port = htons(port);
  1537.                                                
  1538.                                                 addr6 = [NSData dataWithBytes:&nativeAddr6 length:sizeof(nativeAddr6)];
  1539.                                         }
  1540.                                         else
  1541.                                         {
  1542.                                                 char ip[INET6_ADDRSTRLEN];
  1543.                                                
  1544.                                                 const char *conversion;
  1545.                                                 conversion = inet_ntop(AF_INET6, &addr->sin6_addr, ip, sizeof(ip));
  1546.                                                
  1547.                                                 if ((conversion != NULL) && (strcmp(ip, iface) == 0))
  1548.                                                 {
  1549.                                                         // IP match
  1550.                                                        
  1551.                                                         struct sockaddr_in6 nativeAddr6 = *addr;
  1552.                                                         nativeAddr6.sin6_port = htons(port);
  1553.                                                        
  1554.                                                         addr6 = [NSData dataWithBytes:&nativeAddr6 length:sizeof(nativeAddr6)];
  1555.                                                 }
  1556.                                         }
  1557.                                 }
  1558.                                
  1559.                                 cursor = cursor->ifa_next;
  1560.                         }
  1561.                        
  1562.                         freeifaddrs(addrs);
  1563.                 }
  1564.         }
  1565.        
  1566.         if (interfaceAddr4Ptr) *interfaceAddr4Ptr = addr4;
  1567.         if (interfaceAddr6Ptr) *interfaceAddr6Ptr = addr6;
  1568. }
  1569.  
  1570. /**
  1571.  * Converts a numeric hostname into its corresponding address.
  1572.  * The hostname is expected to be an IPv4 or IPv6 address represented as a human-readable string. (e.g. 192.168.4.34)
  1573. **/
  1574. - (void)convertNumericHost:(NSString *)numericHost
  1575.                       port:(uint16_t)port
  1576.               intoAddress4:(NSData **)addr4Ptr
  1577.                   address6:(NSData **)addr6Ptr
  1578. {
  1579.         NSData *addr4 = nil;
  1580.         NSData *addr6 = nil;
  1581.        
  1582.         if (numericHost)
  1583.         {
  1584.                 NSString *portStr = [NSString stringWithFormat:@"%hu", port];
  1585.                
  1586.                 struct addrinfo hints, *res, *res0;
  1587.                
  1588.                 memset(&hints, 0, sizeof(hints));
  1589.                 hints.ai_family   = PF_UNSPEC;
  1590.                 hints.ai_socktype = SOCK_DGRAM;
  1591.                 hints.ai_protocol = IPPROTO_UDP;
  1592.                 hints.ai_flags    = AI_NUMERICHOST; // No name resolution should be attempted
  1593.                
  1594.                 if (getaddrinfo([numericHost UTF8String], [portStr UTF8String], &hints, &res0) == 0)
  1595.                 {
  1596.                         for (res = res0; res; res = res->ai_next)
  1597.                         {
  1598.                                 if ((addr4 == nil) && (res->ai_family == AF_INET))
  1599.                                 {
  1600.                                         // Found IPv4 address
  1601.                                         // Wrap the native address structure
  1602.                                         addr4 = [NSData dataWithBytes:res->ai_addr length:res->ai_addrlen];
  1603.                                 }
  1604.                                 else if ((addr6 == nil) && (res->ai_family == AF_INET6))
  1605.                                 {
  1606.                                         // Found IPv6 address
  1607.                                         // Wrap the native address structure
  1608.                                         addr6 = [NSData dataWithBytes:res->ai_addr length:res->ai_addrlen];
  1609.                                 }
  1610.                         }
  1611.                         freeaddrinfo(res0);
  1612.                 }
  1613.         }
  1614.        
  1615.         if (addr4Ptr) *addr4Ptr = addr4;
  1616.         if (addr6Ptr) *addr6Ptr = addr6;
  1617. }
  1618.  
  1619. - (BOOL)isConnectedToAddress4:(NSData *)someAddr4
  1620. {
  1621.         NSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @"Must be dispatched on socketQueue");
  1622.         NSAssert(flags & kDidConnect, @"Not connected");
  1623.         NSAssert(cachedConnectedAddress, @"Expected cached connected address");
  1624.        
  1625.         if (cachedConnectedFamily != AF_INET)
  1626.         {
  1627.                 return NO;
  1628.         }
  1629.        
  1630.         const struct sockaddr_in *sSockaddr4 = (const struct sockaddr_in *)[someAddr4 bytes];
  1631.         const struct sockaddr_in *cSockaddr4 = (const struct sockaddr_in *)[cachedConnectedAddress bytes];
  1632.        
  1633.         if (memcmp(&sSockaddr4->sin_addr, &cSockaddr4->sin_addr, sizeof(struct in_addr)) != 0)
  1634.         {
  1635.                 return NO;
  1636.         }
  1637.         if (memcmp(&sSockaddr4->sin_port, &cSockaddr4->sin_port, sizeof(in_port_t)) != 0)
  1638.         {
  1639.                 return NO;
  1640.         }
  1641.        
  1642.         return YES;
  1643. }
  1644.  
  1645. - (BOOL)isConnectedToAddress6:(NSData *)someAddr6
  1646. {
  1647.         NSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @"Must be dispatched on socketQueue");
  1648.         NSAssert(flags & kDidConnect, @"Not connected");
  1649.         NSAssert(cachedConnectedAddress, @"Expected cached connected address");
  1650.        
  1651.         if (cachedConnectedFamily != AF_INET6)
  1652.         {
  1653.                 return NO;
  1654.         }
  1655.        
  1656.         const struct sockaddr_in6 *sSockaddr6 = (const struct sockaddr_in6 *)[someAddr6 bytes];
  1657.         const struct sockaddr_in6 *cSockaddr6 = (const struct sockaddr_in6 *)[cachedConnectedAddress bytes];
  1658.        
  1659.         if (memcmp(&sSockaddr6->sin6_addr, &cSockaddr6->sin6_addr, sizeof(struct in6_addr)) != 0)
  1660.         {
  1661.                 return NO;
  1662.         }
  1663.         if (memcmp(&sSockaddr6->sin6_port, &cSockaddr6->sin6_port, sizeof(in_port_t)) != 0)
  1664.         {
  1665.                 return NO;
  1666.         }
  1667.        
  1668.         return YES;
  1669. }
  1670.  
  1671. - (unsigned int)indexOfInterfaceAddr4:(NSData *)interfaceAddr4
  1672. {
  1673.         if (interfaceAddr4 == nil)
  1674.                 return 0;
  1675.         if ([interfaceAddr4 length] != sizeof(struct sockaddr_in))
  1676.                 return 0;
  1677.        
  1678.         int result = 0;
  1679.         const struct sockaddr_in *ifaceAddr = (const struct sockaddr_in *)[interfaceAddr4 bytes];
  1680.        
  1681.         struct ifaddrs *addrs;
  1682.         const struct ifaddrs *cursor;
  1683.        
  1684.         if ((getifaddrs(&addrs) == 0))
  1685.         {
  1686.                 cursor = addrs;
  1687.                 while (cursor != NULL)
  1688.                 {
  1689.                         if (cursor->ifa_addr->sa_family == AF_INET)
  1690.                         {
  1691.                                 // IPv4
  1692.                                
  1693.                                 const struct sockaddr_in *addr = (const struct sockaddr_in *)(const void *)cursor->ifa_addr;
  1694.                                
  1695.                                 if (memcmp(&addr->sin_addr, &ifaceAddr->sin_addr, sizeof(struct in_addr)) == 0)
  1696.                                 {
  1697.                                         result = if_nametoindex(cursor->ifa_name);
  1698.                                         break;
  1699.                                 }
  1700.                         }
  1701.                        
  1702.                         cursor = cursor->ifa_next;
  1703.                 }
  1704.                
  1705.                 freeifaddrs(addrs);
  1706.         }
  1707.        
  1708.         return result;
  1709. }
  1710.  
  1711. - (unsigned int)indexOfInterfaceAddr6:(NSData *)interfaceAddr6
  1712. {
  1713.         if (interfaceAddr6 == nil)
  1714.                 return 0;
  1715.         if ([interfaceAddr6 length] != sizeof(struct sockaddr_in6))
  1716.                 return 0;
  1717.        
  1718.         int result = 0;
  1719.         const struct sockaddr_in6 *ifaceAddr = (const struct sockaddr_in6 *)[interfaceAddr6 bytes];
  1720.        
  1721.         struct ifaddrs *addrs;
  1722.         const struct ifaddrs *cursor;
  1723.        
  1724.         if ((getifaddrs(&addrs) == 0))
  1725.         {
  1726.                 cursor = addrs;
  1727.                 while (cursor != NULL)
  1728.                 {
  1729.                         if (cursor->ifa_addr->sa_family == AF_INET6)
  1730.                         {
  1731.                                 // IPv6
  1732.                                
  1733.                                 const struct sockaddr_in6 *addr = (const struct sockaddr_in6 *)(const void *)cursor->ifa_addr;
  1734.                                
  1735.                                 if (memcmp(&addr->sin6_addr, &ifaceAddr->sin6_addr, sizeof(struct in6_addr)) == 0)
  1736.                                 {
  1737.                                         result = if_nametoindex(cursor->ifa_name);
  1738.                                         break;
  1739.                                 }
  1740.                         }
  1741.                        
  1742.                         cursor = cursor->ifa_next;
  1743.                 }
  1744.                
  1745.                 freeifaddrs(addrs);
  1746.         }
  1747.        
  1748.         return result;
  1749. }
  1750.  
  1751. - (void)setupSendAndReceiveSourcesForSocket4
  1752. {
  1753.         LogTrace();
  1754.         NSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @"Must be dispatched on socketQueue");
  1755.        
  1756.         send4Source = dispatch_source_create(DISPATCH_SOURCE_TYPE_WRITE, socket4FD, 0, socketQueue);
  1757.         receive4Source = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, socket4FD, 0, socketQueue);
  1758.        
  1759.         // Setup event handlers
  1760.        
  1761.         dispatch_source_set_event_handler(send4Source, ^{ @autoreleasepool {
  1762.                
  1763.                 LogVerbose(@"send4EventBlock");
  1764.                 LogVerbose(@"dispatch_source_get_data(send4Source) = %lu", dispatch_source_get_data(send4Source));
  1765.                
  1766.         self->flags |= kSock4CanAcceptBytes;
  1767.                
  1768.                 // If we're ready to send data, do so immediately.
  1769.                 // Otherwise pause the send source or it will continue to fire over and over again.
  1770.                
  1771.         if (self->currentSend == nil)
  1772.                 {
  1773.                         LogVerbose(@"Nothing to send");
  1774.                         [self suspendSend4Source];
  1775.                 }
  1776.         else if (self->currentSend->resolveInProgress)
  1777.                 {
  1778.                         LogVerbose(@"currentSend - waiting for address resolve");
  1779.                         [self suspendSend4Source];
  1780.                 }
  1781.         else if (self->currentSend->filterInProgress)
  1782.                 {
  1783.                         LogVerbose(@"currentSend - waiting on sendFilter");
  1784.                         [self suspendSend4Source];
  1785.                 }
  1786.                 else
  1787.                 {
  1788.                         [self doSend];
  1789.                 }
  1790.                
  1791.         }});
  1792.        
  1793.         dispatch_source_set_event_handler(receive4Source, ^{ @autoreleasepool {
  1794.                
  1795.                 LogVerbose(@"receive4EventBlock");
  1796.                
  1797.         self->socket4FDBytesAvailable = dispatch_source_get_data(self->receive4Source);
  1798.                 LogVerbose(@"socket4FDBytesAvailable: %lu", socket4FDBytesAvailable);
  1799.                
  1800.         if (self->socket4FDBytesAvailable > 0)
  1801.                         [self doReceive];
  1802.                 else
  1803.                         [self doReceiveEOF];
  1804.                
  1805.         }});
  1806.        
  1807.         // Setup cancel handlers
  1808.        
  1809.         __block int socketFDRefCount = 2;
  1810.        
  1811.         int theSocketFD = socket4FD;
  1812.        
  1813.         #if !OS_OBJECT_USE_OBJC
  1814.         dispatch_source_t theSendSource = send4Source;
  1815.         dispatch_source_t theReceiveSource = receive4Source;
  1816.         #endif
  1817.        
  1818.         dispatch_source_set_cancel_handler(send4Source, ^{
  1819.                
  1820.                 LogVerbose(@"send4CancelBlock");
  1821.                
  1822.                 #if !OS_OBJECT_USE_OBJC
  1823.                 LogVerbose(@"dispatch_release(send4Source)");
  1824.                 dispatch_release(theSendSource);
  1825.                 #endif
  1826.                
  1827.                 if (--socketFDRefCount == 0)
  1828.                 {
  1829.                         LogVerbose(@"close(socket4FD)");
  1830.                         close(theSocketFD);
  1831.                 }
  1832.         });
  1833.        
  1834.         dispatch_source_set_cancel_handler(receive4Source, ^{
  1835.                
  1836.                 LogVerbose(@"receive4CancelBlock");
  1837.                
  1838.                 #if !OS_OBJECT_USE_OBJC
  1839.                 LogVerbose(@"dispatch_release(receive4Source)");
  1840.                 dispatch_release(theReceiveSource);
  1841.                 #endif
  1842.                
  1843.                 if (--socketFDRefCount == 0)
  1844.                 {
  1845.                         LogVerbose(@"close(socket4FD)");
  1846.                         close(theSocketFD);
  1847.                 }
  1848.         });
  1849.        
  1850.         // We will not be able to receive until the socket is bound to a port,
  1851.         // either explicitly via bind, or implicitly by connect or by sending data.
  1852.         //
  1853.         // But we should be able to send immediately.
  1854.        
  1855.         socket4FDBytesAvailable = 0;
  1856.         flags |= kSock4CanAcceptBytes;
  1857.        
  1858.         flags |= kSend4SourceSuspended;
  1859.         flags |= kReceive4SourceSuspended;
  1860. }
  1861.  
  1862. - (void)setupSendAndReceiveSourcesForSocket6
  1863. {
  1864.         LogTrace();
  1865.         NSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @"Must be dispatched on socketQueue");
  1866.        
  1867.         send6Source = dispatch_source_create(DISPATCH_SOURCE_TYPE_WRITE, socket6FD, 0, socketQueue);
  1868.         receive6Source = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, socket6FD, 0, socketQueue);
  1869.        
  1870.         // Setup event handlers
  1871.        
  1872.         dispatch_source_set_event_handler(send6Source, ^{ @autoreleasepool {
  1873.                
  1874.                 LogVerbose(@"send6EventBlock");
  1875.                 LogVerbose(@"dispatch_source_get_data(send6Source) = %lu", dispatch_source_get_data(send6Source));
  1876.                
  1877.         self->flags |= kSock6CanAcceptBytes;
  1878.                
  1879.                 // If we're ready to send data, do so immediately.
  1880.                 // Otherwise pause the send source or it will continue to fire over and over again.
  1881.                
  1882.         if (self->currentSend == nil)
  1883.                 {
  1884.                         LogVerbose(@"Nothing to send");
  1885.                         [self suspendSend6Source];
  1886.                 }
  1887.         else if (self->currentSend->resolveInProgress)
  1888.                 {
  1889.                         LogVerbose(@"currentSend - waiting for address resolve");
  1890.                         [self suspendSend6Source];
  1891.                 }
  1892.         else if (self->currentSend->filterInProgress)
  1893.                 {
  1894.                         LogVerbose(@"currentSend - waiting on sendFilter");
  1895.                         [self suspendSend6Source];
  1896.                 }
  1897.                 else
  1898.                 {
  1899.                         [self doSend];
  1900.                 }
  1901.                
  1902.         }});
  1903.        
  1904.         dispatch_source_set_event_handler(receive6Source, ^{ @autoreleasepool {
  1905.                
  1906.                 LogVerbose(@"receive6EventBlock");
  1907.                
  1908.         self->socket6FDBytesAvailable = dispatch_source_get_data(self->receive6Source);
  1909.                 LogVerbose(@"socket6FDBytesAvailable: %lu", socket6FDBytesAvailable);
  1910.                
  1911.         if (self->socket6FDBytesAvailable > 0)
  1912.                         [self doReceive];
  1913.                 else
  1914.                         [self doReceiveEOF];
  1915.                
  1916.         }});
  1917.        
  1918.         // Setup cancel handlers
  1919.        
  1920.         __block int socketFDRefCount = 2;
  1921.        
  1922.         int theSocketFD = socket6FD;
  1923.        
  1924.         #if !OS_OBJECT_USE_OBJC
  1925.         dispatch_source_t theSendSource = send6Source;
  1926.         dispatch_source_t theReceiveSource = receive6Source;
  1927.         #endif
  1928.        
  1929.         dispatch_source_set_cancel_handler(send6Source, ^{
  1930.                
  1931.                 LogVerbose(@"send6CancelBlock");
  1932.                
  1933.                 #if !OS_OBJECT_USE_OBJC
  1934.                 LogVerbose(@"dispatch_release(send6Source)");
  1935.                 dispatch_release(theSendSource);
  1936.                 #endif
  1937.                
  1938.                 if (--socketFDRefCount == 0)
  1939.                 {
  1940.                         LogVerbose(@"close(socket6FD)");
  1941.                         close(theSocketFD);
  1942.                 }
  1943.         });
  1944.        
  1945.         dispatch_source_set_cancel_handler(receive6Source, ^{
  1946.                
  1947.                 LogVerbose(@"receive6CancelBlock");
  1948.                
  1949.                 #if !OS_OBJECT_USE_OBJC
  1950.                 LogVerbose(@"dispatch_release(receive6Source)");
  1951.                 dispatch_release(theReceiveSource);
  1952.                 #endif
  1953.                
  1954.                 if (--socketFDRefCount == 0)
  1955.                 {
  1956.                         LogVerbose(@"close(socket6FD)");
  1957.                         close(theSocketFD);
  1958.                 }
  1959.         });
  1960.        
  1961.         // We will not be able to receive until the socket is bound to a port,
  1962.         // either explicitly via bind, or implicitly by connect or by sending data.
  1963.         //
  1964.         // But we should be able to send immediately.
  1965.        
  1966.         socket6FDBytesAvailable = 0;
  1967.         flags |= kSock6CanAcceptBytes;
  1968.        
  1969.         flags |= kSend6SourceSuspended;
  1970.         flags |= kReceive6SourceSuspended;
  1971. }
  1972.  
  1973. - (BOOL)createSocket4:(BOOL)useIPv4 socket6:(BOOL)useIPv6 error:(NSError * __autoreleasing *)errPtr
  1974. {
  1975.         LogTrace();
  1976.        
  1977.         NSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @"Must be dispatched on socketQueue");
  1978.         NSAssert(((flags & kDidCreateSockets) == 0), @"Sockets have already been created");
  1979.        
  1980.         // CreateSocket Block
  1981.         // This block will be invoked below.
  1982.        
  1983.         int(^createSocket)(int) = ^int (int domain) {
  1984.                
  1985.                 int socketFD = socket(domain, SOCK_DGRAM, 0);
  1986.                
  1987.                 if (socketFD == SOCKET_NULL)
  1988.                 {
  1989.                         if (errPtr)
  1990.                                 *errPtr = [self errnoErrorWithReason:@"Error in socket() function"];
  1991.                        
  1992.                         return SOCKET_NULL;
  1993.                 }
  1994.                
  1995.                 int status;
  1996.                
  1997.                 // Set socket options
  1998.                
  1999.                 status = fcntl(socketFD, F_SETFL, O_NONBLOCK);
  2000.                 if (status == -1)
  2001.                 {
  2002.                         if (errPtr)
  2003.                                 *errPtr = [self errnoErrorWithReason:@"Error enabling non-blocking IO on socket (fcntl)"];
  2004.                        
  2005.                         close(socketFD);
  2006.                         return SOCKET_NULL;
  2007.                 }
  2008.                
  2009.                 int reuseaddr = 1;
  2010.                 status = setsockopt(socketFD, SOL_SOCKET, SO_REUSEADDR, &reuseaddr, sizeof(reuseaddr));
  2011.                 if (status == -1)
  2012.                 {
  2013.                         if (errPtr)
  2014.                                 *errPtr = [self errnoErrorWithReason:@"Error enabling address reuse (setsockopt)"];
  2015.                        
  2016.                         close(socketFD);
  2017.                         return SOCKET_NULL;
  2018.                 }
  2019.                
  2020.                 int nosigpipe = 1;
  2021.                 status = setsockopt(socketFD, SOL_SOCKET, SO_NOSIGPIPE, &nosigpipe, sizeof(nosigpipe));
  2022.                 if (status == -1)
  2023.                 {
  2024.                         if (errPtr)
  2025.                                 *errPtr = [self errnoErrorWithReason:@"Error disabling sigpipe (setsockopt)"];
  2026.                        
  2027.                         close(socketFD);
  2028.                         return SOCKET_NULL;
  2029.                 }
  2030.        
  2031.         /**
  2032.          * The theoretical maximum size of any IPv4 UDP packet is UINT16_MAX = 65535.
  2033.          * The theoretical maximum size of any IPv6 UDP packet is UINT32_MAX = 4294967295.
  2034.          *
  2035.          * The default maximum size of the UDP buffer in iOS is 9216 bytes.
  2036.          *
  2037.          * This is the reason of #222(GCD does not necessarily return the size of an entire UDP packet) and
  2038.          *  #535(GCDAsyncUDPSocket can not send data when data is greater than 9K)
  2039.          *
  2040.          *
  2041.          * Enlarge the maximum size of UDP packet.
  2042.          * I can not ensure the protocol type now so that the max size is set to 65535 :)
  2043.          **/
  2044.      
  2045.         status = setsockopt(socketFD, SOL_SOCKET, SO_SNDBUF, (const char*)&self->maxSendSize, sizeof(int));
  2046.         if (status == -1)
  2047.         {
  2048.             if (errPtr)
  2049.                 *errPtr = [self errnoErrorWithReason:@"Error setting send buffer size (setsockopt)"];
  2050.             close(socketFD);
  2051.             return SOCKET_NULL;
  2052.         }
  2053.        
  2054.         status = setsockopt(socketFD, SOL_SOCKET, SO_RCVBUF, (const char*)&self->maxSendSize, sizeof(int));
  2055.         if (status == -1)
  2056.         {
  2057.             if (errPtr)
  2058.                 *errPtr = [self errnoErrorWithReason:@"Error setting receive buffer size (setsockopt)"];
  2059.             close(socketFD);
  2060.             return SOCKET_NULL;
  2061.         }
  2062.  
  2063.                
  2064.                 return socketFD;
  2065.         };
  2066.        
  2067.         // Create sockets depending upon given configuration.
  2068.        
  2069.         if (useIPv4)
  2070.         {
  2071.                 LogVerbose(@"Creating IPv4 socket");
  2072.                
  2073.                 socket4FD = createSocket(AF_INET);
  2074.                 if (socket4FD == SOCKET_NULL)
  2075.                 {
  2076.                         // errPtr set in local createSocket() block
  2077.                         return NO;
  2078.                 }
  2079.         }
  2080.        
  2081.         if (useIPv6)
  2082.         {
  2083.                 LogVerbose(@"Creating IPv6 socket");
  2084.                
  2085.                 socket6FD = createSocket(AF_INET6);
  2086.                 if (socket6FD == SOCKET_NULL)
  2087.                 {
  2088.                         // errPtr set in local createSocket() block
  2089.                        
  2090.                         if (socket4FD != SOCKET_NULL)
  2091.                         {
  2092.                                 close(socket4FD);
  2093.                                 socket4FD = SOCKET_NULL;
  2094.                         }
  2095.                        
  2096.                         return NO;
  2097.                 }
  2098.         }
  2099.        
  2100.         // Setup send and receive sources
  2101.        
  2102.         if (useIPv4)
  2103.                 [self setupSendAndReceiveSourcesForSocket4];
  2104.         if (useIPv6)
  2105.                 [self setupSendAndReceiveSourcesForSocket6];
  2106.        
  2107.         flags |= kDidCreateSockets;
  2108.         return YES;
  2109. }
  2110.  
  2111. - (BOOL)createSockets:(NSError **)errPtr
  2112. {
  2113.         LogTrace();
  2114.        
  2115.         BOOL useIPv4 = [self isIPv4Enabled];
  2116.         BOOL useIPv6 = [self isIPv6Enabled];
  2117.        
  2118.         return [self createSocket4:useIPv4 socket6:useIPv6 error:errPtr];
  2119. }
  2120.  
  2121. - (void)suspendSend4Source
  2122. {
  2123.         if (send4Source && !(flags & kSend4SourceSuspended))
  2124.         {
  2125.                 LogVerbose(@"dispatch_suspend(send4Source)");
  2126.                
  2127.                 dispatch_suspend(send4Source);
  2128.                 flags |= kSend4SourceSuspended;
  2129.         }
  2130. }
  2131.  
  2132. - (void)suspendSend6Source
  2133. {
  2134.         if (send6Source && !(flags & kSend6SourceSuspended))
  2135.         {
  2136.                 LogVerbose(@"dispatch_suspend(send6Source)");
  2137.                
  2138.                 dispatch_suspend(send6Source);
  2139.                 flags |= kSend6SourceSuspended;
  2140.         }
  2141. }
  2142.  
  2143. - (void)resumeSend4Source
  2144. {
  2145.         if (send4Source && (flags & kSend4SourceSuspended))
  2146.         {
  2147.                 LogVerbose(@"dispatch_resume(send4Source)");
  2148.                
  2149.                 dispatch_resume(send4Source);
  2150.                 flags &= ~kSend4SourceSuspended;
  2151.         }
  2152. }
  2153.  
  2154. - (void)resumeSend6Source
  2155. {
  2156.         if (send6Source && (flags & kSend6SourceSuspended))
  2157.         {
  2158.                 LogVerbose(@"dispatch_resume(send6Source)");
  2159.                
  2160.                 dispatch_resume(send6Source);
  2161.                 flags &= ~kSend6SourceSuspended;
  2162.         }
  2163. }
  2164.  
  2165. - (void)suspendReceive4Source
  2166. {
  2167.         if (receive4Source && !(flags & kReceive4SourceSuspended))
  2168.         {
  2169.                 LogVerbose(@"dispatch_suspend(receive4Source)");
  2170.                
  2171.                 dispatch_suspend(receive4Source);
  2172.                 flags |= kReceive4SourceSuspended;
  2173.         }
  2174. }
  2175.  
  2176. - (void)suspendReceive6Source
  2177. {
  2178.         if (receive6Source && !(flags & kReceive6SourceSuspended))
  2179.         {
  2180.                 LogVerbose(@"dispatch_suspend(receive6Source)");
  2181.                
  2182.                 dispatch_suspend(receive6Source);
  2183.                 flags |= kReceive6SourceSuspended;
  2184.         }
  2185. }
  2186.  
  2187. - (void)resumeReceive4Source
  2188. {
  2189.         if (receive4Source && (flags & kReceive4SourceSuspended))
  2190.         {
  2191.                 LogVerbose(@"dispatch_resume(receive4Source)");
  2192.                
  2193.                 dispatch_resume(receive4Source);
  2194.                 flags &= ~kReceive4SourceSuspended;
  2195.         }
  2196. }
  2197.  
  2198. - (void)resumeReceive6Source
  2199. {
  2200.         if (receive6Source && (flags & kReceive6SourceSuspended))
  2201.         {
  2202.                 LogVerbose(@"dispatch_resume(receive6Source)");
  2203.                
  2204.                 dispatch_resume(receive6Source);
  2205.                 flags &= ~kReceive6SourceSuspended;
  2206.         }
  2207. }
  2208.  
  2209. - (void)closeSocket4
  2210. {
  2211.         if (socket4FD != SOCKET_NULL)
  2212.         {
  2213.                 LogVerbose(@"dispatch_source_cancel(send4Source)");
  2214.                 dispatch_source_cancel(send4Source);
  2215.                
  2216.                 LogVerbose(@"dispatch_source_cancel(receive4Source)");
  2217.                 dispatch_source_cancel(receive4Source);
  2218.                
  2219.                 // For some crazy reason (in my opinion), cancelling a dispatch source doesn't
  2220.                 // invoke the cancel handler if the dispatch source is paused.
  2221.                 // So we have to unpause the source if needed.
  2222.                 // This allows the cancel handler to be run, which in turn releases the source and closes the socket.
  2223.                
  2224.                 [self resumeSend4Source];
  2225.                 [self resumeReceive4Source];
  2226.                
  2227.                 // The sockets will be closed by the cancel handlers of the corresponding source
  2228.                
  2229.                 send4Source = NULL;
  2230.                 receive4Source = NULL;
  2231.                
  2232.                 socket4FD = SOCKET_NULL;
  2233.                
  2234.                 // Clear socket states
  2235.                
  2236.                 socket4FDBytesAvailable = 0;
  2237.                 flags &= ~kSock4CanAcceptBytes;
  2238.                
  2239.                 // Clear cached info
  2240.                
  2241.                 cachedLocalAddress4 = nil;
  2242.                 cachedLocalHost4 = nil;
  2243.                 cachedLocalPort4 = 0;
  2244.         }
  2245. }
  2246.  
  2247. - (void)closeSocket6
  2248. {
  2249.         if (socket6FD != SOCKET_NULL)
  2250.         {
  2251.                 LogVerbose(@"dispatch_source_cancel(send6Source)");
  2252.                 dispatch_source_cancel(send6Source);
  2253.                
  2254.                 LogVerbose(@"dispatch_source_cancel(receive6Source)");
  2255.                 dispatch_source_cancel(receive6Source);
  2256.                
  2257.                 // For some crazy reason (in my opinion), cancelling a dispatch source doesn't
  2258.                 // invoke the cancel handler if the dispatch source is paused.
  2259.                 // So we have to unpause the source if needed.
  2260.                 // This allows the cancel handler to be run, which in turn releases the source and closes the socket.
  2261.                
  2262.                 [self resumeSend6Source];
  2263.                 [self resumeReceive6Source];
  2264.                
  2265.                 send6Source = NULL;
  2266.                 receive6Source = NULL;
  2267.                
  2268.                 // The sockets will be closed by the cancel handlers of the corresponding source
  2269.                
  2270.                 socket6FD = SOCKET_NULL;
  2271.                
  2272.                 // Clear socket states
  2273.                
  2274.                 socket6FDBytesAvailable = 0;
  2275.                 flags &= ~kSock6CanAcceptBytes;
  2276.                
  2277.                 // Clear cached info
  2278.                
  2279.                 cachedLocalAddress6 = nil;
  2280.                 cachedLocalHost6 = nil;
  2281.                 cachedLocalPort6 = 0;
  2282.         }
  2283. }
  2284.  
  2285. - (void)closeSockets
  2286. {
  2287.         [self closeSocket4];
  2288.         [self closeSocket6];
  2289.        
  2290.         flags &= ~kDidCreateSockets;
  2291. }
  2292.  
  2293. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2294. #pragma mark Diagnostics
  2295. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2296.  
  2297. - (BOOL)getLocalAddress:(NSData **)dataPtr
  2298.                    host:(NSString **)hostPtr
  2299.                    port:(uint16_t *)portPtr
  2300.               forSocket:(int)socketFD
  2301.              withFamily:(int)socketFamily
  2302. {
  2303.        
  2304.         NSData   *data = nil;
  2305.         NSString *host = nil;
  2306.         uint16_t  port = 0;
  2307.        
  2308.         if (socketFamily == AF_INET)
  2309.         {
  2310.                 struct sockaddr_in sockaddr4;
  2311.                 socklen_t sockaddr4len = sizeof(sockaddr4);
  2312.                
  2313.                 if (getsockname(socketFD, (struct sockaddr *)&sockaddr4, &sockaddr4len) == 0)
  2314.                 {
  2315.                         data = [NSData dataWithBytes:&sockaddr4 length:sockaddr4len];
  2316.                         host = [[self class] hostFromSockaddr4:&sockaddr4];
  2317.                         port = [[self class] portFromSockaddr4:&sockaddr4];
  2318.                 }
  2319.                 else
  2320.                 {
  2321.                         LogWarn(@"Error in getsockname: %@", [self errnoError]);
  2322.                 }
  2323.         }
  2324.         else if (socketFamily == AF_INET6)
  2325.         {
  2326.                 struct sockaddr_in6 sockaddr6;
  2327.                 socklen_t sockaddr6len = sizeof(sockaddr6);
  2328.                
  2329.                 if (getsockname(socketFD, (struct sockaddr *)&sockaddr6, &sockaddr6len) == 0)
  2330.                 {
  2331.                         data = [NSData dataWithBytes:&sockaddr6 length:sockaddr6len];
  2332.                         host = [[self class] hostFromSockaddr6:&sockaddr6];
  2333.                         port = [[self class] portFromSockaddr6:&sockaddr6];
  2334.                 }
  2335.                 else
  2336.                 {
  2337.                         LogWarn(@"Error in getsockname: %@", [self errnoError]);
  2338.                 }
  2339.         }
  2340.        
  2341.         if (dataPtr) *dataPtr = data;
  2342.         if (hostPtr) *hostPtr = host;
  2343.         if (portPtr) *portPtr = port;
  2344.        
  2345.         return (data != nil);
  2346. }
  2347.  
  2348. - (void)maybeUpdateCachedLocalAddress4Info
  2349. {
  2350.         NSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @"Must be dispatched on socketQueue");
  2351.        
  2352.         if ( cachedLocalAddress4 || ((flags & kDidBind) == 0) || (socket4FD == SOCKET_NULL) )
  2353.         {
  2354.                 return;
  2355.         }
  2356.        
  2357.         NSData *address = nil;
  2358.         NSString *host = nil;
  2359.         uint16_t port = 0;
  2360.        
  2361.         if ([self getLocalAddress:&address host:&host port:&port forSocket:socket4FD withFamily:AF_INET])
  2362.         {
  2363.                
  2364.                 cachedLocalAddress4 = address;
  2365.                 cachedLocalHost4 = host;
  2366.                 cachedLocalPort4 = port;
  2367.         }
  2368. }
  2369.  
  2370. - (void)maybeUpdateCachedLocalAddress6Info
  2371. {
  2372.         NSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @"Must be dispatched on socketQueue");
  2373.        
  2374.         if ( cachedLocalAddress6 || ((flags & kDidBind) == 0) || (socket6FD == SOCKET_NULL) )
  2375.         {
  2376.                 return;
  2377.         }
  2378.        
  2379.         NSData *address = nil;
  2380.         NSString *host = nil;
  2381.         uint16_t port = 0;
  2382.        
  2383.         if ([self getLocalAddress:&address host:&host port:&port forSocket:socket6FD withFamily:AF_INET6])
  2384.         {
  2385.                
  2386.                 cachedLocalAddress6 = address;
  2387.                 cachedLocalHost6 = host;
  2388.                 cachedLocalPort6 = port;
  2389.         }
  2390. }
  2391.  
  2392. - (NSData *)localAddress
  2393. {
  2394.         __block NSData *result = nil;
  2395.        
  2396.         dispatch_block_t block = ^{
  2397.                
  2398.         if (self->socket4FD != SOCKET_NULL)
  2399.                 {
  2400.                         [self maybeUpdateCachedLocalAddress4Info];
  2401.             result = self->cachedLocalAddress4;
  2402.                 }
  2403.                 else
  2404.                 {
  2405.                         [self maybeUpdateCachedLocalAddress6Info];
  2406.             result = self->cachedLocalAddress6;
  2407.                 }
  2408.                
  2409.         };
  2410.        
  2411.         if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
  2412.                 block();
  2413.         else
  2414.                 dispatch_sync(socketQueue, AutoreleasedBlock(block));
  2415.        
  2416.         return result;
  2417. }
  2418.  
  2419. - (NSString *)localHost
  2420. {
  2421.         __block NSString *result = nil;
  2422.        
  2423.         dispatch_block_t block = ^{
  2424.                
  2425.         if (self->socket4FD != SOCKET_NULL)
  2426.                 {
  2427.                         [self maybeUpdateCachedLocalAddress4Info];
  2428.             result = self->cachedLocalHost4;
  2429.                 }
  2430.                 else
  2431.                 {
  2432.                         [self maybeUpdateCachedLocalAddress6Info];
  2433.             result = self->cachedLocalHost6;
  2434.                 }
  2435.         };
  2436.        
  2437.         if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
  2438.                 block();
  2439.         else
  2440.                 dispatch_sync(socketQueue, AutoreleasedBlock(block));
  2441.        
  2442.         return result;
  2443. }
  2444.  
  2445. - (uint16_t)localPort
  2446. {
  2447.         __block uint16_t result = 0;
  2448.        
  2449.         dispatch_block_t block = ^{
  2450.                
  2451.         if (self->socket4FD != SOCKET_NULL)
  2452.                 {
  2453.                         [self maybeUpdateCachedLocalAddress4Info];
  2454.             result = self->cachedLocalPort4;
  2455.                 }
  2456.                 else
  2457.                 {
  2458.                         [self maybeUpdateCachedLocalAddress6Info];
  2459.             result = self->cachedLocalPort6;
  2460.                 }
  2461.         };
  2462.        
  2463.         if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
  2464.                 block();
  2465.         else
  2466.                 dispatch_sync(socketQueue, AutoreleasedBlock(block));
  2467.        
  2468.         return result;
  2469. }
  2470.  
  2471. - (NSData *)localAddress_IPv4
  2472. {
  2473.         __block NSData *result = nil;
  2474.        
  2475.         dispatch_block_t block = ^{
  2476.                
  2477.                 [self maybeUpdateCachedLocalAddress4Info];
  2478.         result = self->cachedLocalAddress4;
  2479.         };
  2480.        
  2481.         if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
  2482.                 block();
  2483.         else
  2484.                 dispatch_sync(socketQueue, AutoreleasedBlock(block));
  2485.        
  2486.         return result;
  2487. }
  2488.  
  2489. - (NSString *)localHost_IPv4
  2490. {
  2491.         __block NSString *result = nil;
  2492.        
  2493.         dispatch_block_t block = ^{
  2494.                
  2495.                 [self maybeUpdateCachedLocalAddress4Info];
  2496.         result = self->cachedLocalHost4;
  2497.         };
  2498.        
  2499.         if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
  2500.                 block();
  2501.         else
  2502.                 dispatch_sync(socketQueue, AutoreleasedBlock(block));
  2503.        
  2504.         return result;
  2505. }
  2506.  
  2507. - (uint16_t)localPort_IPv4
  2508. {
  2509.         __block uint16_t result = 0;
  2510.        
  2511.         dispatch_block_t block = ^{
  2512.                
  2513.                 [self maybeUpdateCachedLocalAddress4Info];
  2514.         result = self->cachedLocalPort4;
  2515.         };
  2516.        
  2517.         if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
  2518.                 block();
  2519.         else
  2520.                 dispatch_sync(socketQueue, AutoreleasedBlock(block));
  2521.        
  2522.         return result;
  2523. }
  2524.  
  2525. - (NSData *)localAddress_IPv6
  2526. {
  2527.         __block NSData *result = nil;
  2528.        
  2529.         dispatch_block_t block = ^{
  2530.                
  2531.                 [self maybeUpdateCachedLocalAddress6Info];
  2532.         result = self->cachedLocalAddress6;
  2533.         };
  2534.        
  2535.         if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
  2536.                 block();
  2537.         else
  2538.                 dispatch_sync(socketQueue, AutoreleasedBlock(block));
  2539.        
  2540.         return result;
  2541. }
  2542.  
  2543. - (NSString *)localHost_IPv6
  2544. {
  2545.         __block NSString *result = nil;
  2546.        
  2547.         dispatch_block_t block = ^{
  2548.                
  2549.                 [self maybeUpdateCachedLocalAddress6Info];
  2550.         result = self->cachedLocalHost6;
  2551.         };
  2552.        
  2553.         if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
  2554.                 block();
  2555.         else
  2556.                 dispatch_sync(socketQueue, AutoreleasedBlock(block));
  2557.        
  2558.         return result;
  2559. }
  2560.  
  2561. - (uint16_t)localPort_IPv6
  2562. {
  2563.         __block uint16_t result = 0;
  2564.        
  2565.         dispatch_block_t block = ^{
  2566.                
  2567.                 [self maybeUpdateCachedLocalAddress6Info];
  2568.         result = self->cachedLocalPort6;
  2569.         };
  2570.        
  2571.         if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
  2572.                 block();
  2573.         else
  2574.                 dispatch_sync(socketQueue, AutoreleasedBlock(block));
  2575.        
  2576.         return result;
  2577. }
  2578.  
  2579. - (void)maybeUpdateCachedConnectedAddressInfo
  2580. {
  2581.         NSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @"Must be dispatched on socketQueue");
  2582.        
  2583.         if (cachedConnectedAddress || (flags & kDidConnect) == 0)
  2584.         {
  2585.                 return;
  2586.         }
  2587.        
  2588.         NSData *data = nil;
  2589.         NSString *host = nil;
  2590.         uint16_t port = 0;
  2591.         int family = AF_UNSPEC;
  2592.        
  2593.         if (socket4FD != SOCKET_NULL)
  2594.         {
  2595.                 struct sockaddr_in sockaddr4;
  2596.                 socklen_t sockaddr4len = sizeof(sockaddr4);
  2597.                
  2598.                 if (getpeername(socket4FD, (struct sockaddr *)&sockaddr4, &sockaddr4len) == 0)
  2599.                 {
  2600.                         data = [NSData dataWithBytes:&sockaddr4 length:sockaddr4len];
  2601.                         host = [[self class] hostFromSockaddr4:&sockaddr4];
  2602.                         port = [[self class] portFromSockaddr4:&sockaddr4];
  2603.                         family = AF_INET;
  2604.                 }
  2605.                 else
  2606.                 {
  2607.                         LogWarn(@"Error in getpeername: %@", [self errnoError]);
  2608.                 }
  2609.         }
  2610.         else if (socket6FD != SOCKET_NULL)
  2611.         {
  2612.                 struct sockaddr_in6 sockaddr6;
  2613.                 socklen_t sockaddr6len = sizeof(sockaddr6);
  2614.                
  2615.                 if (getpeername(socket6FD, (struct sockaddr *)&sockaddr6, &sockaddr6len) == 0)
  2616.                 {
  2617.                         data = [NSData dataWithBytes:&sockaddr6 length:sockaddr6len];
  2618.                         host = [[self class] hostFromSockaddr6:&sockaddr6];
  2619.                         port = [[self class] portFromSockaddr6:&sockaddr6];
  2620.                         family = AF_INET6;
  2621.                 }
  2622.                 else
  2623.                 {
  2624.                         LogWarn(@"Error in getpeername: %@", [self errnoError]);
  2625.                 }
  2626.         }
  2627.        
  2628.        
  2629.         cachedConnectedAddress = data;
  2630.         cachedConnectedHost    = host;
  2631.         cachedConnectedPort    = port;
  2632.         cachedConnectedFamily  = family;
  2633. }
  2634.  
  2635. - (NSData *)connectedAddress
  2636. {
  2637.         __block NSData *result = nil;
  2638.        
  2639.         dispatch_block_t block = ^{
  2640.                
  2641.                 [self maybeUpdateCachedConnectedAddressInfo];
  2642.         result = self->cachedConnectedAddress;
  2643.         };
  2644.        
  2645.         if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
  2646.                 block();
  2647.         else
  2648.                 dispatch_sync(socketQueue, AutoreleasedBlock(block));
  2649.        
  2650.         return result;
  2651. }
  2652.  
  2653. - (NSString *)connectedHost
  2654. {
  2655.         __block NSString *result = nil;
  2656.        
  2657.         dispatch_block_t block = ^{
  2658.                
  2659.                 [self maybeUpdateCachedConnectedAddressInfo];
  2660.         result = self->cachedConnectedHost;
  2661.         };
  2662.        
  2663.         if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
  2664.                 block();
  2665.         else
  2666.                 dispatch_sync(socketQueue, AutoreleasedBlock(block));
  2667.        
  2668.         return result;
  2669. }
  2670.  
  2671. - (uint16_t)connectedPort
  2672. {
  2673.         __block uint16_t result = 0;
  2674.        
  2675.         dispatch_block_t block = ^{
  2676.                
  2677.                 [self maybeUpdateCachedConnectedAddressInfo];
  2678.         result = self->cachedConnectedPort;
  2679.         };
  2680.        
  2681.         if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
  2682.                 block();
  2683.         else
  2684.                 dispatch_sync(socketQueue, AutoreleasedBlock(block));
  2685.        
  2686.         return result;
  2687. }
  2688.  
  2689. - (BOOL)isConnected
  2690. {
  2691.         __block BOOL result = NO;
  2692.        
  2693.         dispatch_block_t block = ^{
  2694.         result = (self->flags & kDidConnect) ? YES : NO;
  2695.         };
  2696.        
  2697.         if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
  2698.                 block();
  2699.         else
  2700.                 dispatch_sync(socketQueue, block);
  2701.        
  2702.         return result;
  2703. }
  2704.  
  2705. - (BOOL)isClosed
  2706. {
  2707.         __block BOOL result = YES;
  2708.        
  2709.         dispatch_block_t block = ^{
  2710.                
  2711.         result = (self->flags & kDidCreateSockets) ? NO : YES;
  2712.         };
  2713.        
  2714.         if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
  2715.                 block();
  2716.         else
  2717.                 dispatch_sync(socketQueue, block);
  2718.        
  2719.         return result;
  2720. }
  2721.  
  2722. - (BOOL)isIPv4
  2723. {
  2724.         __block BOOL result = NO;
  2725.        
  2726.         dispatch_block_t block = ^{
  2727.                
  2728.         if (self->flags & kDidCreateSockets)
  2729.                 {
  2730.             result = (self->socket4FD != SOCKET_NULL);
  2731.                 }
  2732.                 else
  2733.                 {
  2734.                         result = [self isIPv4Enabled];
  2735.                 }
  2736.         };
  2737.        
  2738.         if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
  2739.                 block();
  2740.         else
  2741.                 dispatch_sync(socketQueue, block);
  2742.        
  2743.         return result;
  2744. }
  2745.  
  2746. - (BOOL)isIPv6
  2747. {
  2748.         __block BOOL result = NO;
  2749.        
  2750.         dispatch_block_t block = ^{
  2751.                
  2752.         if (self->flags & kDidCreateSockets)
  2753.                 {
  2754.             result = (self->socket6FD != SOCKET_NULL);
  2755.                 }
  2756.                 else
  2757.                 {
  2758.                         result = [self isIPv6Enabled];
  2759.                 }
  2760.         };
  2761.        
  2762.         if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
  2763.                 block();
  2764.         else
  2765.                 dispatch_sync(socketQueue, block);
  2766.        
  2767.         return result;
  2768. }
  2769.  
  2770. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2771. #pragma mark Binding
  2772. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2773.  
  2774. /**
  2775.  * This method runs through the various checks required prior to a bind attempt.
  2776.  * It is shared between the various bind methods.
  2777. **/
  2778. - (BOOL)preBind:(NSError **)errPtr
  2779. {
  2780.         if (![self preOp:errPtr])
  2781.         {
  2782.                 return NO;
  2783.         }
  2784.        
  2785.         if (flags & kDidBind)
  2786.         {
  2787.                 if (errPtr)
  2788.                 {
  2789.                         NSString *msg = @"Cannot bind a socket more than once.";
  2790.                         *errPtr = [self badConfigError:msg];
  2791.                 }
  2792.                 return NO;
  2793.         }
  2794.        
  2795.         if ((flags & kConnecting) || (flags & kDidConnect))
  2796.         {
  2797.                 if (errPtr)
  2798.                 {
  2799.                         NSString *msg = @"Cannot bind after connecting. If needed, bind first, then connect.";
  2800.                         *errPtr = [self badConfigError:msg];
  2801.                 }
  2802.                 return NO;
  2803.         }
  2804.        
  2805.         BOOL isIPv4Disabled = (config & kIPv4Disabled) ? YES : NO;
  2806.         BOOL isIPv6Disabled = (config & kIPv6Disabled) ? YES : NO;
  2807.        
  2808.         if (isIPv4Disabled && isIPv6Disabled) // Must have IPv4 or IPv6 enabled
  2809.         {
  2810.                 if (errPtr)
  2811.                 {
  2812.                         NSString *msg = @"Both IPv4 and IPv6 have been disabled. Must enable at least one protocol first.";
  2813.                         *errPtr = [self badConfigError:msg];
  2814.                 }
  2815.                 return NO;
  2816.         }
  2817.        
  2818.         return YES;
  2819. }
  2820.  
  2821. - (BOOL)bindToPort:(uint16_t)port error:(NSError **)errPtr
  2822. {
  2823.         return [self bindToPort:port interface:nil error:errPtr];
  2824. }
  2825.  
  2826. - (BOOL)bindToPort:(uint16_t)port interface:(NSString *)interface error:(NSError **)errPtr
  2827. {
  2828.         __block BOOL result = NO;
  2829.         __block NSError *err = nil;
  2830.        
  2831.         dispatch_block_t block = ^{ @autoreleasepool {
  2832.                
  2833.                 // Run through sanity checks
  2834.                
  2835.                 if (![self preBind:&err])
  2836.                 {
  2837.                         return_from_block;
  2838.                 }
  2839.                
  2840.                 // Check the given interface
  2841.                
  2842.                 NSData *interface4 = nil;
  2843.                 NSData *interface6 = nil;
  2844.                
  2845.                 [self convertIntefaceDescription:interface port:port intoAddress4:&interface4 address6:&interface6];
  2846.                
  2847.                 if ((interface4 == nil) && (interface6 == nil))
  2848.                 {
  2849.                         NSString *msg = @"Unknown interface. Specify valid interface by name (e.g. \"en1\") or IP address.";
  2850.                         err = [self badParamError:msg];
  2851.                        
  2852.                         return_from_block;
  2853.                 }
  2854.                
  2855.         BOOL isIPv4Disabled = (self->config & kIPv4Disabled) ? YES : NO;
  2856.         BOOL isIPv6Disabled = (self->config & kIPv6Disabled) ? YES : NO;
  2857.                
  2858.                 if (isIPv4Disabled && (interface6 == nil))
  2859.                 {
  2860.                         NSString *msg = @"IPv4 has been disabled and specified interface doesn't support IPv6.";
  2861.                         err = [self badParamError:msg];
  2862.                        
  2863.                         return_from_block;
  2864.                 }
  2865.                
  2866.                 if (isIPv6Disabled && (interface4 == nil))
  2867.                 {
  2868.                         NSString *msg = @"IPv6 has been disabled and specified interface doesn't support IPv4.";
  2869.                         err = [self badParamError:msg];
  2870.                        
  2871.                         return_from_block;
  2872.                 }
  2873.                
  2874.                 // Determine protocol(s)
  2875.                
  2876.                 BOOL useIPv4 = !isIPv4Disabled && (interface4 != nil);
  2877.                 BOOL useIPv6 = !isIPv6Disabled && (interface6 != nil);
  2878.                
  2879.                 // Create the socket(s) if needed
  2880.                
  2881.         if ((self->flags & kDidCreateSockets) == 0)
  2882.                 {
  2883.                         if (![self createSocket4:useIPv4 socket6:useIPv6 error:&err])
  2884.                         {
  2885.                                 return_from_block;
  2886.                         }
  2887.                 }
  2888.                
  2889.                 // Bind the socket(s)
  2890.                
  2891.                 LogVerbose(@"Binding socket to port(%hu) interface(%@)", port, interface);
  2892.                
  2893.                 if (useIPv4)
  2894.                 {
  2895.             int status = bind(self->socket4FD, (const struct sockaddr *)[interface4 bytes], (socklen_t)[interface4 length]);
  2896.                         if (status == -1)
  2897.                         {
  2898.                                 [self closeSockets];
  2899.                                
  2900.                                 NSString *reason = @"Error in bind() function";
  2901.                                 err = [self errnoErrorWithReason:reason];
  2902.                                
  2903.                                 return_from_block;
  2904.                         }
  2905.                 }
  2906.                
  2907.                 if (useIPv6)
  2908.                 {
  2909.             int status = bind(self->socket6FD, (const struct sockaddr *)[interface6 bytes], (socklen_t)[interface6 length]);
  2910.                         if (status == -1)
  2911.                         {
  2912.                                 [self closeSockets];
  2913.                                
  2914.                                 NSString *reason = @"Error in bind() function";
  2915.                                 err = [self errnoErrorWithReason:reason];
  2916.                                
  2917.                                 return_from_block;
  2918.                         }
  2919.                 }
  2920.                
  2921.                 // Update flags
  2922.                
  2923.         self->flags |= kDidBind;
  2924.                
  2925.         if (!useIPv4) self->flags |= kIPv4Deactivated;
  2926.         if (!useIPv6) self->flags |= kIPv6Deactivated;
  2927.                
  2928.                 result = YES;
  2929.                
  2930.         }};
  2931.        
  2932.         if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
  2933.                 block();
  2934.         else
  2935.                 dispatch_sync(socketQueue, block);
  2936.        
  2937.         if (err)
  2938.                 LogError(@"Error binding to port/interface: %@", err);
  2939.        
  2940.         if (errPtr)
  2941.                 *errPtr = err;
  2942.        
  2943.         return result;
  2944. }
  2945.  
  2946. - (BOOL)bindToAddress:(NSData *)localAddr error:(NSError **)errPtr
  2947. {
  2948.         __block BOOL result = NO;
  2949.         __block NSError *err = nil;
  2950.        
  2951.         dispatch_block_t block = ^{ @autoreleasepool {
  2952.                
  2953.                 // Run through sanity checks
  2954.                
  2955.                 if (![self preBind:&err])
  2956.                 {
  2957.                         return_from_block;
  2958.                 }
  2959.                
  2960.                 // Check the given address
  2961.                
  2962.                 int addressFamily = [[self class] familyFromAddress:localAddr];
  2963.                
  2964.                 if (addressFamily == AF_UNSPEC)
  2965.                 {
  2966.                         NSString *msg = @"A valid IPv4 or IPv6 address was not given";
  2967.                         err = [self badParamError:msg];
  2968.                        
  2969.                         return_from_block;
  2970.                 }
  2971.                
  2972.                 NSData *localAddr4 = (addressFamily == AF_INET)  ? localAddr : nil;
  2973.                 NSData *localAddr6 = (addressFamily == AF_INET6) ? localAddr : nil;
  2974.                
  2975.         BOOL isIPv4Disabled = (self->config & kIPv4Disabled) ? YES : NO;
  2976.         BOOL isIPv6Disabled = (self->config & kIPv6Disabled) ? YES : NO;
  2977.                
  2978.                 if (isIPv4Disabled && localAddr4)
  2979.                 {
  2980.                         NSString *msg = @"IPv4 has been disabled and an IPv4 address was passed.";
  2981.                         err = [self badParamError:msg];
  2982.                        
  2983.                         return_from_block;
  2984.                 }
  2985.                
  2986.                 if (isIPv6Disabled && localAddr6)
  2987.                 {
  2988.                         NSString *msg = @"IPv6 has been disabled and an IPv6 address was passed.";
  2989.                         err = [self badParamError:msg];
  2990.                        
  2991.                         return_from_block;
  2992.                 }
  2993.                
  2994.                 // Determine protocol(s)
  2995.                
  2996.                 BOOL useIPv4 = !isIPv4Disabled && (localAddr4 != nil);
  2997.                 BOOL useIPv6 = !isIPv6Disabled && (localAddr6 != nil);
  2998.                
  2999.                 // Create the socket(s) if needed
  3000.                
  3001.         if ((self->flags & kDidCreateSockets) == 0)
  3002.                 {
  3003.                         if (![self createSocket4:useIPv4 socket6:useIPv6 error:&err])
  3004.                         {
  3005.                                 return_from_block;
  3006.                         }
  3007.                 }
  3008.                
  3009.                 // Bind the socket(s)
  3010.                
  3011.                 if (useIPv4)
  3012.                 {
  3013.                         LogVerbose(@"Binding socket to address(%@:%hu)",
  3014.                                            [[self class] hostFromAddress:localAddr4],
  3015.                                            [[self class] portFromAddress:localAddr4]);
  3016.                        
  3017.             int status = bind(self->socket4FD, (const struct sockaddr *)[localAddr4 bytes], (socklen_t)[localAddr4 length]);
  3018.                         if (status == -1)
  3019.                         {
  3020.                                 [self closeSockets];
  3021.                                
  3022.                                 NSString *reason = @"Error in bind() function";
  3023.                                 err = [self errnoErrorWithReason:reason];
  3024.                                
  3025.                                 return_from_block;
  3026.                         }
  3027.                 }
  3028.                 else
  3029.                 {
  3030.                         LogVerbose(@"Binding socket to address(%@:%hu)",
  3031.                                            [[self class] hostFromAddress:localAddr6],
  3032.                                            [[self class] portFromAddress:localAddr6]);
  3033.                        
  3034.             int status = bind(self->socket6FD, (const struct sockaddr *)[localAddr6 bytes], (socklen_t)[localAddr6 length]);
  3035.                         if (status == -1)
  3036.                         {
  3037.                                 [self closeSockets];
  3038.                                
  3039.                                 NSString *reason = @"Error in bind() function";
  3040.                                 err = [self errnoErrorWithReason:reason];
  3041.                                
  3042.                                 return_from_block;
  3043.                         }
  3044.                 }
  3045.                
  3046.                 // Update flags
  3047.                
  3048.         self->flags |= kDidBind;
  3049.                
  3050.         if (!useIPv4) self->flags |= kIPv4Deactivated;
  3051.         if (!useIPv6) self->flags |= kIPv6Deactivated;
  3052.                
  3053.                 result = YES;
  3054.                
  3055.         }};
  3056.        
  3057.         if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
  3058.                 block();
  3059.         else
  3060.                 dispatch_sync(socketQueue, block);
  3061.        
  3062.         if (err)
  3063.                 LogError(@"Error binding to address: %@", err);
  3064.        
  3065.         if (errPtr)
  3066.                 *errPtr = err;
  3067.        
  3068.         return result;
  3069. }
  3070.  
  3071. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3072. #pragma mark Connecting
  3073. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3074.  
  3075. /**
  3076.  * This method runs through the various checks required prior to a connect attempt.
  3077.  * It is shared between the various connect methods.
  3078. **/
  3079. - (BOOL)preConnect:(NSError **)errPtr
  3080. {
  3081.         if (![self preOp:errPtr])
  3082.         {
  3083.                 return NO;
  3084.         }
  3085.        
  3086.         if ((flags & kConnecting) || (flags & kDidConnect))
  3087.         {
  3088.                 if (errPtr)
  3089.                 {
  3090.                         NSString *msg = @"Cannot connect a socket more than once.";
  3091.                         *errPtr = [self badConfigError:msg];
  3092.                 }
  3093.                 return NO;
  3094.         }
  3095.        
  3096.         BOOL isIPv4Disabled = (config & kIPv4Disabled) ? YES : NO;
  3097.         BOOL isIPv6Disabled = (config & kIPv6Disabled) ? YES : NO;
  3098.        
  3099.         if (isIPv4Disabled && isIPv6Disabled) // Must have IPv4 or IPv6 enabled
  3100.         {
  3101.                 if (errPtr)
  3102.                 {
  3103.                         NSString *msg = @"Both IPv4 and IPv6 have been disabled. Must enable at least one protocol first.";
  3104.                         *errPtr = [self badConfigError:msg];
  3105.                 }
  3106.                 return NO;
  3107.         }
  3108.        
  3109.         return YES;
  3110. }
  3111.  
  3112. - (BOOL)connectToHost:(NSString *)host onPort:(uint16_t)port error:(NSError **)errPtr
  3113. {
  3114.         __block BOOL result = NO;
  3115.         __block NSError *err = nil;
  3116.        
  3117.         dispatch_block_t block = ^{ @autoreleasepool {
  3118.                
  3119.                 // Run through sanity checks.
  3120.                
  3121.                 if (![self preConnect:&err])
  3122.                 {
  3123.                         return_from_block;
  3124.                 }
  3125.                
  3126.                 // Check parameter(s)
  3127.                
  3128.                 if (host == nil)
  3129.                 {
  3130.                         NSString *msg = @"The host param is nil. Should be domain name or IP address string.";
  3131.                         err = [self badParamError:msg];
  3132.                        
  3133.                         return_from_block;
  3134.                 }
  3135.                
  3136.                 // Create the socket(s) if needed
  3137.                
  3138.         if ((self->flags & kDidCreateSockets) == 0)
  3139.                 {
  3140.                         if (![self createSockets:&err])
  3141.                         {
  3142.                                 return_from_block;
  3143.                         }
  3144.                 }
  3145.                
  3146.                 // Create special connect packet
  3147.                
  3148.                 GCDAsyncUdpSpecialPacket *packet = [[GCDAsyncUdpSpecialPacket alloc] init];
  3149.                 packet->resolveInProgress = YES;
  3150.                
  3151.                 // Start asynchronous DNS resolve for host:port on background queue
  3152.                
  3153.                 LogVerbose(@"Dispatching DNS resolve for connect...");
  3154.                
  3155.                 [self asyncResolveHost:host port:port withCompletionBlock:^(NSArray *addresses, NSError *error) {
  3156.                        
  3157.                         // The asyncResolveHost:port:: method asynchronously dispatches a task onto the global concurrent queue,
  3158.                         // and immediately returns. Once the async resolve task completes,
  3159.                         // this block is executed on our socketQueue.
  3160.                        
  3161.                         packet->resolveInProgress = NO;
  3162.                        
  3163.                         packet->addresses = addresses;
  3164.                         packet->error = error;
  3165.                        
  3166.                         [self maybeConnect];
  3167.                 }];
  3168.                
  3169.                 // Updates flags, add connect packet to send queue, and pump send queue
  3170.                
  3171.         self->flags |= kConnecting;
  3172.                
  3173.         [self->sendQueue addObject:packet];
  3174.                 [self maybeDequeueSend];
  3175.                
  3176.                 result = YES;
  3177.         }};
  3178.        
  3179.         if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
  3180.                 block();
  3181.         else
  3182.                 dispatch_sync(socketQueue, block);
  3183.        
  3184.         if (err)
  3185.                 LogError(@"Error connecting to host/port: %@", err);
  3186.        
  3187.         if (errPtr)
  3188.                 *errPtr = err;
  3189.        
  3190.         return result;
  3191. }
  3192.  
  3193. - (BOOL)connectToAddress:(NSData *)remoteAddr error:(NSError **)errPtr
  3194. {
  3195.         __block BOOL result = NO;
  3196.         __block NSError *err = nil;
  3197.        
  3198.         dispatch_block_t block = ^{ @autoreleasepool {
  3199.                
  3200.                 // Run through sanity checks.
  3201.                
  3202.                 if (![self preConnect:&err])
  3203.                 {
  3204.                         return_from_block;
  3205.                 }
  3206.                
  3207.                 // Check parameter(s)
  3208.                
  3209.                 if (remoteAddr == nil)
  3210.                 {
  3211.                         NSString *msg = @"The address param is nil. Should be a valid address.";
  3212.                         err = [self badParamError:msg];
  3213.                        
  3214.                         return_from_block;
  3215.                 }
  3216.                
  3217.                 // Create the socket(s) if needed
  3218.                
  3219.         if ((self->flags & kDidCreateSockets) == 0)
  3220.                 {
  3221.                         if (![self createSockets:&err])
  3222.                         {
  3223.                                 return_from_block;
  3224.                         }
  3225.                 }
  3226.                
  3227.                 // The remoteAddr parameter could be of type NSMutableData.
  3228.                 // So we copy it to be safe.
  3229.                
  3230.                 NSData *address = [remoteAddr copy];
  3231.                 NSArray *addresses = [NSArray arrayWithObject:address];
  3232.                
  3233.                 GCDAsyncUdpSpecialPacket *packet = [[GCDAsyncUdpSpecialPacket alloc] init];
  3234.                 packet->addresses = addresses;
  3235.                
  3236.                 // Updates flags, add connect packet to send queue, and pump send queue
  3237.                
  3238.         self->flags |= kConnecting;
  3239.                
  3240.         [self->sendQueue addObject:packet];
  3241.                 [self maybeDequeueSend];
  3242.                
  3243.                 result = YES;
  3244.         }};
  3245.        
  3246.         if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
  3247.                 block();
  3248.         else
  3249.                 dispatch_sync(socketQueue, block);
  3250.        
  3251.         if (err)
  3252.                 LogError(@"Error connecting to address: %@", err);
  3253.        
  3254.         if (errPtr)
  3255.                 *errPtr = err;
  3256.        
  3257.         return result;
  3258. }
  3259.  
  3260. - (void)maybeConnect
  3261. {
  3262.         LogTrace();
  3263.         NSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @"Must be dispatched on socketQueue");
  3264.        
  3265.        
  3266.         BOOL sendQueueReady = [currentSend isKindOfClass:[GCDAsyncUdpSpecialPacket class]];
  3267.        
  3268.         if (sendQueueReady)
  3269.         {
  3270.                 GCDAsyncUdpSpecialPacket *connectPacket = (GCDAsyncUdpSpecialPacket *)currentSend;
  3271.                
  3272.                 if (connectPacket->resolveInProgress)
  3273.                 {
  3274.                         LogVerbose(@"Waiting for DNS resolve...");
  3275.                 }
  3276.                 else
  3277.                 {
  3278.                         if (connectPacket->error)
  3279.                         {
  3280.                                 [self notifyDidNotConnect:connectPacket->error];
  3281.                         }
  3282.                         else
  3283.                         {
  3284.                                 NSData *address = nil;
  3285.                                 NSError *error = nil;
  3286.                                
  3287.                                 int addressFamily = [self getAddress:&address error:&error fromAddresses:connectPacket->addresses];
  3288.                                
  3289.                                 // Perform connect
  3290.                                
  3291.                                 BOOL result = NO;
  3292.                                
  3293.                                 switch (addressFamily)
  3294.                                 {
  3295.                                         case AF_INET  : result = [self connectWithAddress4:address error:&error]; break;
  3296.                                         case AF_INET6 : result = [self connectWithAddress6:address error:&error]; break;
  3297.                                 }
  3298.                                
  3299.                                 if (result)
  3300.                                 {
  3301.                                         flags |= kDidBind;
  3302.                                         flags |= kDidConnect;
  3303.                                        
  3304.                                         cachedConnectedAddress = address;
  3305.                                         cachedConnectedHost = [[self class] hostFromAddress:address];
  3306.                                         cachedConnectedPort = [[self class] portFromAddress:address];
  3307.                                         cachedConnectedFamily = addressFamily;
  3308.                                        
  3309.                                         [self notifyDidConnectToAddress:address];
  3310.                                 }
  3311.                                 else
  3312.                                 {
  3313.                                         [self notifyDidNotConnect:error];
  3314.                                 }
  3315.                         }
  3316.                        
  3317.                         flags &= ~kConnecting;
  3318.                        
  3319.                         [self endCurrentSend];
  3320.                         [self maybeDequeueSend];
  3321.                 }
  3322.         }
  3323. }
  3324.  
  3325. - (BOOL)connectWithAddress4:(NSData *)address4 error:(NSError **)errPtr
  3326. {
  3327.         LogTrace();
  3328.         NSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @"Must be dispatched on socketQueue");
  3329.        
  3330.         int status = connect(socket4FD, (const struct sockaddr *)[address4 bytes], (socklen_t)[address4 length]);
  3331.         if (status != 0)
  3332.         {
  3333.                 if (errPtr)
  3334.                         *errPtr = [self errnoErrorWithReason:@"Error in connect() function"];
  3335.                
  3336.                 return NO;
  3337.         }
  3338.        
  3339.         [self closeSocket6];
  3340.         flags |= kIPv6Deactivated;
  3341.        
  3342.         return YES;
  3343. }
  3344.  
  3345. - (BOOL)connectWithAddress6:(NSData *)address6 error:(NSError **)errPtr
  3346. {
  3347.         LogTrace();
  3348.         NSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @"Must be dispatched on socketQueue");
  3349.        
  3350.         int status = connect(socket6FD, (const struct sockaddr *)[address6 bytes], (socklen_t)[address6 length]);
  3351.         if (status != 0)
  3352.         {
  3353.                 if (errPtr)
  3354.                         *errPtr = [self errnoErrorWithReason:@"Error in connect() function"];
  3355.                
  3356.                 return NO;
  3357.         }
  3358.        
  3359.         [self closeSocket4];
  3360.         flags |= kIPv4Deactivated;
  3361.        
  3362.         return YES;
  3363. }
  3364.  
  3365. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3366. #pragma mark Multicast
  3367. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3368.  
  3369. - (BOOL)preJoin:(NSError **)errPtr
  3370. {
  3371.         if (![self preOp:errPtr])
  3372.         {
  3373.                 return NO;
  3374.         }
  3375.        
  3376.         if (!(flags & kDidBind))
  3377.         {
  3378.                 if (errPtr)
  3379.                 {
  3380.                         NSString *msg = @"Must bind a socket before joining a multicast group.";
  3381.                         *errPtr = [self badConfigError:msg];
  3382.                 }
  3383.                 return NO;
  3384.         }
  3385.        
  3386.         if ((flags & kConnecting) || (flags & kDidConnect))
  3387.         {
  3388.                 if (errPtr)
  3389.                 {
  3390.                         NSString *msg = @"Cannot join a multicast group if connected.";
  3391.                         *errPtr = [self badConfigError:msg];
  3392.                 }
  3393.                 return NO;
  3394.         }
  3395.        
  3396.         return YES;
  3397. }
  3398.  
  3399. - (BOOL)joinMulticastGroup:(NSString *)group error:(NSError **)errPtr
  3400. {
  3401.         return [self joinMulticastGroup:group onInterface:nil error:errPtr];
  3402. }
  3403.  
  3404. - (BOOL)joinMulticastGroup:(NSString *)group onInterface:(NSString *)interface error:(NSError **)errPtr
  3405. {
  3406.     // IP_ADD_MEMBERSHIP == IPV6_JOIN_GROUP
  3407.     return [self performMulticastRequest:IP_ADD_MEMBERSHIP forGroup:group onInterface:interface error:errPtr];
  3408. }
  3409.  
  3410. - (BOOL)leaveMulticastGroup:(NSString *)group error:(NSError **)errPtr
  3411. {
  3412.         return [self leaveMulticastGroup:group onInterface:nil error:errPtr];
  3413. }
  3414.  
  3415. - (BOOL)leaveMulticastGroup:(NSString *)group onInterface:(NSString *)interface error:(NSError **)errPtr
  3416. {
  3417.     // IP_DROP_MEMBERSHIP == IPV6_LEAVE_GROUP
  3418.     return [self performMulticastRequest:IP_DROP_MEMBERSHIP forGroup:group onInterface:interface error:errPtr];
  3419. }
  3420.  
  3421. - (BOOL)performMulticastRequest:(int)requestType
  3422.                        forGroup:(NSString *)group
  3423.                     onInterface:(NSString *)interface
  3424.                           error:(NSError **)errPtr
  3425. {
  3426.         __block BOOL result = NO;
  3427.         __block NSError *err = nil;
  3428.        
  3429.         dispatch_block_t block = ^{ @autoreleasepool {
  3430.                
  3431.                 // Run through sanity checks
  3432.                
  3433.                 if (![self preJoin:&err])
  3434.                 {
  3435.                         return_from_block;
  3436.                 }
  3437.                
  3438.                 // Convert group to address
  3439.                
  3440.                 NSData *groupAddr4 = nil;
  3441.                 NSData *groupAddr6 = nil;
  3442.                
  3443.                 [self convertNumericHost:group port:0 intoAddress4:&groupAddr4 address6:&groupAddr6];
  3444.                
  3445.                 if ((groupAddr4 == nil) && (groupAddr6 == nil))
  3446.                 {
  3447.                         NSString *msg = @"Unknown group. Specify valid group IP address.";
  3448.                         err = [self badParamError:msg];
  3449.                        
  3450.                         return_from_block;
  3451.                 }
  3452.                
  3453.                 // Convert interface to address
  3454.                
  3455.                 NSData *interfaceAddr4 = nil;
  3456.                 NSData *interfaceAddr6 = nil;
  3457.                
  3458.                 [self convertIntefaceDescription:interface port:0 intoAddress4:&interfaceAddr4 address6:&interfaceAddr6];
  3459.                
  3460.                 if ((interfaceAddr4 == nil) && (interfaceAddr6 == nil))
  3461.                 {
  3462.                         NSString *msg = @"Unknown interface. Specify valid interface by name (e.g. \"en1\") or IP address.";
  3463.                         err = [self badParamError:msg];
  3464.                        
  3465.                         return_from_block;
  3466.                 }
  3467.                
  3468.                 // Perform join
  3469.                
  3470.         if ((self->socket4FD != SOCKET_NULL) && groupAddr4 && interfaceAddr4)
  3471.                 {
  3472.                         const struct sockaddr_in *nativeGroup = (const struct sockaddr_in *)[groupAddr4 bytes];
  3473.                         const struct sockaddr_in *nativeIface = (const struct sockaddr_in *)[interfaceAddr4 bytes];
  3474.                        
  3475.                         struct ip_mreq imreq;
  3476.                         imreq.imr_multiaddr = nativeGroup->sin_addr;
  3477.                         imreq.imr_interface = nativeIface->sin_addr;
  3478.                        
  3479.             int status = setsockopt(self->socket4FD, IPPROTO_IP, requestType, (const void *)&imreq, sizeof(imreq));
  3480.                         if (status != 0)
  3481.                         {
  3482.                                 err = [self errnoErrorWithReason:@"Error in setsockopt() function"];
  3483.                                
  3484.                                 return_from_block;
  3485.                         }
  3486.                        
  3487.                         // Using IPv4 only
  3488.                         [self closeSocket6];
  3489.                        
  3490.                         result = YES;
  3491.                 }
  3492.         else if ((self->socket6FD != SOCKET_NULL) && groupAddr6 && interfaceAddr6)
  3493.                 {
  3494.                         const struct sockaddr_in6 *nativeGroup = (const struct sockaddr_in6 *)[groupAddr6 bytes];
  3495.                        
  3496.                         struct ipv6_mreq imreq;
  3497.                         imreq.ipv6mr_multiaddr = nativeGroup->sin6_addr;
  3498.                         imreq.ipv6mr_interface = [self indexOfInterfaceAddr6:interfaceAddr6];
  3499.                        
  3500.             int status = setsockopt(self->socket6FD, IPPROTO_IPV6, requestType, (const void *)&imreq, sizeof(imreq));
  3501.                         if (status != 0)
  3502.                         {
  3503.                                 err = [self errnoErrorWithReason:@"Error in setsockopt() function"];
  3504.                                
  3505.                                 return_from_block;
  3506.                         }
  3507.                        
  3508.                         // Using IPv6 only
  3509.                         [self closeSocket4];
  3510.                        
  3511.                         result = YES;
  3512.                 }
  3513.                 else
  3514.                 {
  3515.                         NSString *msg = @"Socket, group, and interface do not have matching IP versions";
  3516.                         err = [self badParamError:msg];
  3517.                        
  3518.                         return_from_block;
  3519.                 }
  3520.                
  3521.         }};
  3522.        
  3523.         if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
  3524.                 block();
  3525.         else
  3526.                 dispatch_sync(socketQueue, block);
  3527.        
  3528.         if (errPtr)
  3529.                 *errPtr = err;
  3530.        
  3531.         return result;
  3532. }
  3533.  
  3534. - (BOOL)sendIPv4MulticastOnInterface:(NSString*)interface error:(NSError **)errPtr
  3535. {
  3536.     __block BOOL result = NO;
  3537.     __block NSError *err = nil;
  3538.  
  3539.     dispatch_block_t block = ^{ @autoreleasepool {
  3540.  
  3541.         if (![self preOp:&err])
  3542.         {
  3543.             return_from_block;
  3544.         }
  3545.  
  3546.         if ((self->flags & kDidCreateSockets) == 0)
  3547.         {
  3548.             if (![self createSockets:&err])
  3549.             {
  3550.                 return_from_block;
  3551.             }
  3552.         }
  3553.        
  3554.         // Convert interface to address
  3555.  
  3556.         NSData *interfaceAddr4 = nil;
  3557.         NSData *interfaceAddr6 = nil;
  3558.  
  3559.         [self convertIntefaceDescription:interface port:0 intoAddress4:&interfaceAddr4 address6:&interfaceAddr6];
  3560.  
  3561.         if (interfaceAddr4 == nil)
  3562.         {
  3563.             NSString *msg = @"Unknown interface. Specify valid interface by IP address.";
  3564.             err = [self badParamError:msg];
  3565.             return_from_block;
  3566.         }
  3567.  
  3568.         if (self->socket4FD != SOCKET_NULL) {
  3569.             const struct sockaddr_in *nativeIface = (struct sockaddr_in *)[interfaceAddr4 bytes];
  3570.             struct in_addr interface_addr = nativeIface->sin_addr;
  3571.             int status = setsockopt(self->socket4FD, IPPROTO_IP, IP_MULTICAST_IF, &interface_addr, sizeof(interface_addr));
  3572.             if (status != 0) {
  3573.                  err = [self errnoErrorWithReason:@"Error in setsockopt() function"];
  3574.                 return_from_block;
  3575.                 result = YES;
  3576.           }
  3577.         }
  3578.        
  3579.      }};
  3580.  
  3581.     if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
  3582.         block();
  3583.     else
  3584.         dispatch_sync(socketQueue, block);
  3585.  
  3586.     if (errPtr)
  3587.         *errPtr = err;
  3588.  
  3589.     return result;
  3590. }
  3591.  
  3592. - (BOOL)sendIPv6MulticastOnInterface:(NSString*)interface error:(NSError **)errPtr
  3593. {
  3594.     __block BOOL result = NO;
  3595.     __block NSError *err = nil;
  3596.  
  3597.     dispatch_block_t block = ^{ @autoreleasepool {
  3598.  
  3599.         if (![self preOp:&err])
  3600.         {
  3601.             return_from_block;
  3602.         }
  3603.  
  3604.         if ((self->flags & kDidCreateSockets) == 0)
  3605.         {
  3606.             if (![self createSockets:&err])
  3607.             {
  3608.                 return_from_block;
  3609.             }
  3610.         }
  3611.        
  3612.         // Convert interface to address
  3613.  
  3614.         NSData *interfaceAddr4 = nil;
  3615.         NSData *interfaceAddr6 = nil;
  3616.  
  3617.         [self convertIntefaceDescription:interface port:0 intoAddress4:&interfaceAddr4 address6:&interfaceAddr6];
  3618.  
  3619.         if (interfaceAddr6 == nil)
  3620.         {
  3621.             NSString *msg = @"Unknown interface. Specify valid interface by name (e.g. \"en1\").";
  3622.             err = [self badParamError:msg];
  3623.             return_from_block;
  3624.         }
  3625.  
  3626.         if ((self->socket6FD != SOCKET_NULL)) {
  3627.             uint32_t scope_id = [self indexOfInterfaceAddr6:interfaceAddr6];
  3628.             int status = setsockopt(self->socket6FD, IPPROTO_IPV6, IPV6_MULTICAST_IF, &scope_id, sizeof(scope_id));
  3629.             if (status != 0) {
  3630.                  err = [self errnoErrorWithReason:@"Error in setsockopt() function"];
  3631.                 return_from_block;
  3632.             }
  3633.             result = YES;
  3634.        }
  3635.        
  3636.      }};
  3637.  
  3638.     if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
  3639.         block();
  3640.     else
  3641.         dispatch_sync(socketQueue, block);
  3642.  
  3643.     if (errPtr)
  3644.         *errPtr = err;
  3645.  
  3646.     return result;
  3647. }
  3648.  
  3649. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3650. #pragma mark Reuse port
  3651. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3652.  
  3653. - (BOOL)enableReusePort:(BOOL)flag error:(NSError **)errPtr
  3654. {
  3655.         __block BOOL result = NO;
  3656.         __block NSError *err = nil;
  3657.        
  3658.         dispatch_block_t block = ^{ @autoreleasepool {
  3659.                
  3660.                 if (![self preOp:&err])
  3661.                 {
  3662.                         return_from_block;
  3663.                 }
  3664.                
  3665.         if ((self->flags & kDidCreateSockets) == 0)
  3666.                 {
  3667.                         if (![self createSockets:&err])
  3668.                         {
  3669.                                 return_from_block;
  3670.                         }
  3671.                 }
  3672.                
  3673.                 int value = flag ? 1 : 0;
  3674.         if (self->socket4FD != SOCKET_NULL)
  3675.                 {
  3676.             int error = setsockopt(self->socket4FD, SOL_SOCKET, SO_REUSEPORT, (const void *)&value, sizeof(value));
  3677.                        
  3678.                         if (error)
  3679.                         {
  3680.                                 err = [self errnoErrorWithReason:@"Error in setsockopt() function"];
  3681.                                
  3682.                                 return_from_block;
  3683.                         }
  3684.                         result = YES;
  3685.                 }
  3686.                
  3687.         if (self->socket6FD != SOCKET_NULL)
  3688.                 {
  3689.             int error = setsockopt(self->socket6FD, SOL_SOCKET, SO_REUSEPORT, (const void *)&value, sizeof(value));
  3690.                        
  3691.                         if (error)
  3692.                         {
  3693.                                 err = [self errnoErrorWithReason:@"Error in setsockopt() function"];
  3694.                                
  3695.                                 return_from_block;
  3696.                         }
  3697.                         result = YES;
  3698.                 }
  3699.                
  3700.         }};
  3701.        
  3702.         if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
  3703.                 block();
  3704.         else
  3705.                 dispatch_sync(socketQueue, block);
  3706.        
  3707.         if (errPtr)
  3708.                 *errPtr = err;
  3709.        
  3710.         return result;
  3711. }
  3712.  
  3713. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3714. #pragma mark Broadcast
  3715. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3716.  
  3717. - (BOOL)enableBroadcast:(BOOL)flag error:(NSError **)errPtr
  3718. {
  3719.         __block BOOL result = NO;
  3720.         __block NSError *err = nil;
  3721.        
  3722.         dispatch_block_t block = ^{ @autoreleasepool {
  3723.                
  3724.                 if (![self preOp:&err])
  3725.                 {
  3726.                         return_from_block;
  3727.                 }
  3728.                
  3729.         if ((self->flags & kDidCreateSockets) == 0)
  3730.                 {
  3731.                         if (![self createSockets:&err])
  3732.                         {
  3733.                                 return_from_block;
  3734.                         }
  3735.                 }
  3736.                
  3737.         if (self->socket4FD != SOCKET_NULL)
  3738.                 {
  3739.                         int value = flag ? 1 : 0;
  3740.             int error = setsockopt(self->socket4FD, SOL_SOCKET, SO_BROADCAST, (const void *)&value, sizeof(value));
  3741.                        
  3742.                         if (error)
  3743.                         {
  3744.                                 err = [self errnoErrorWithReason:@"Error in setsockopt() function"];
  3745.                                
  3746.                                 return_from_block;
  3747.                         }
  3748.                         result = YES;
  3749.                 }
  3750.                
  3751.                 // IPv6 does not implement broadcast, the ability to send a packet to all hosts on the attached link.
  3752.                 // The same effect can be achieved by sending a packet to the link-local all hosts multicast group.
  3753.                
  3754.         }};
  3755.        
  3756.         if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
  3757.                 block();
  3758.         else
  3759.                 dispatch_sync(socketQueue, block);
  3760.        
  3761.         if (errPtr)
  3762.                 *errPtr = err;
  3763.        
  3764.         return result;
  3765. }
  3766.  
  3767. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3768. #pragma mark Sending
  3769. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3770.  
  3771. - (void)sendData:(NSData *)data withTag:(long)tag
  3772. {
  3773.         [self sendData:data withTimeout:-1.0 tag:tag];
  3774. }
  3775.  
  3776. - (void)sendData:(NSData *)data withTimeout:(NSTimeInterval)timeout tag:(long)tag
  3777. {
  3778.         LogTrace();
  3779.        
  3780.         if ([data length] == 0)
  3781.         {
  3782.                 LogWarn(@"Ignoring attempt to send nil/empty data.");
  3783.                 return;
  3784.         }
  3785.    
  3786.    
  3787.        
  3788.         GCDAsyncUdpSendPacket *packet = [[GCDAsyncUdpSendPacket alloc] initWithData:data timeout:timeout tag:tag];
  3789.        
  3790.         dispatch_async(socketQueue, ^{ @autoreleasepool {
  3791.                
  3792.         [self->sendQueue addObject:packet];
  3793.                 [self maybeDequeueSend];
  3794.         }});
  3795.        
  3796. }
  3797.  
  3798. - (void)sendData:(NSData *)data
  3799.           toHost:(NSString *)host
  3800.             port:(uint16_t)port
  3801.      withTimeout:(NSTimeInterval)timeout
  3802.              tag:(long)tag
  3803. {
  3804.         LogTrace();
  3805.        
  3806.         if ([data length] == 0)
  3807.         {
  3808.                 LogWarn(@"Ignoring attempt to send nil/empty data.");
  3809.                 return;
  3810.         }
  3811.        
  3812.         GCDAsyncUdpSendPacket *packet = [[GCDAsyncUdpSendPacket alloc] initWithData:data timeout:timeout tag:tag];
  3813.         packet->resolveInProgress = YES;
  3814.        
  3815.         [self asyncResolveHost:host port:port withCompletionBlock:^(NSArray *addresses, NSError *error) {
  3816.                
  3817.                 // The asyncResolveHost:port:: method asynchronously dispatches a task onto the global concurrent queue,
  3818.                 // and immediately returns. Once the async resolve task completes,
  3819.                 // this block is executed on our socketQueue.
  3820.                
  3821.                 packet->resolveInProgress = NO;
  3822.                
  3823.                 packet->resolvedAddresses = addresses;
  3824.                 packet->resolveError = error;
  3825.                
  3826.         if (packet == self->currentSend)
  3827.                 {
  3828.                         LogVerbose(@"currentSend - address resolved");
  3829.                         [self doPreSend];
  3830.                 }
  3831.         }];
  3832.        
  3833.         dispatch_async(socketQueue, ^{ @autoreleasepool {
  3834.                
  3835.         [self->sendQueue addObject:packet];
  3836.                 [self maybeDequeueSend];
  3837.                
  3838.         }});
  3839.        
  3840. }
  3841.  
  3842. - (void)sendData:(NSData *)data toAddress:(NSData *)remoteAddr withTimeout:(NSTimeInterval)timeout tag:(long)tag
  3843. {
  3844.         LogTrace();
  3845.        
  3846.         if ([data length] == 0)
  3847.         {
  3848.                 LogWarn(@"Ignoring attempt to send nil/empty data.");
  3849.                 return;
  3850.         }
  3851.        
  3852.         GCDAsyncUdpSendPacket *packet = [[GCDAsyncUdpSendPacket alloc] initWithData:data timeout:timeout tag:tag];
  3853.         packet->addressFamily = [GCDAsyncUdpSocket familyFromAddress:remoteAddr];
  3854.         packet->address = remoteAddr;
  3855.        
  3856.         dispatch_async(socketQueue, ^{ @autoreleasepool {
  3857.                
  3858.         [self->sendQueue addObject:packet];
  3859.                 [self maybeDequeueSend];
  3860.         }});
  3861. }
  3862.  
  3863. - (void)setSendFilter:(GCDAsyncUdpSocketSendFilterBlock)filterBlock withQueue:(dispatch_queue_t)filterQueue
  3864. {
  3865.         [self setSendFilter:filterBlock withQueue:filterQueue isAsynchronous:YES];
  3866. }
  3867.  
  3868. - (void)setSendFilter:(GCDAsyncUdpSocketSendFilterBlock)filterBlock
  3869.             withQueue:(dispatch_queue_t)filterQueue
  3870.        isAsynchronous:(BOOL)isAsynchronous
  3871. {
  3872.         GCDAsyncUdpSocketSendFilterBlock newFilterBlock = NULL;
  3873.         dispatch_queue_t newFilterQueue = NULL;
  3874.        
  3875.         if (filterBlock)
  3876.         {
  3877.                 NSAssert(filterQueue, @"Must provide a dispatch_queue in which to run the filter block.");
  3878.                
  3879.                 newFilterBlock = [filterBlock copy];
  3880.                 newFilterQueue = filterQueue;
  3881.                 #if !OS_OBJECT_USE_OBJC
  3882.                 dispatch_retain(newFilterQueue);
  3883.                 #endif
  3884.         }
  3885.        
  3886.         dispatch_block_t block = ^{
  3887.                
  3888.                 #if !OS_OBJECT_USE_OBJC
  3889.         if (self->sendFilterQueue) dispatch_release(self->sendFilterQueue);
  3890.                 #endif
  3891.                
  3892.         self->sendFilterBlock = newFilterBlock;
  3893.         self->sendFilterQueue = newFilterQueue;
  3894.         self->sendFilterAsync = isAsynchronous;
  3895.         };
  3896.        
  3897.         if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
  3898.                 block();
  3899.         else
  3900.                 dispatch_async(socketQueue, block);
  3901. }
  3902.  
  3903. - (void)maybeDequeueSend
  3904. {
  3905.         LogTrace();
  3906.         NSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @"Must be dispatched on socketQueue");
  3907.        
  3908.         // If we don't have a send operation already in progress
  3909.         if (currentSend == nil)
  3910.         {
  3911.                 // Create the sockets if needed
  3912.                 if ((flags & kDidCreateSockets) == 0)
  3913.                 {
  3914.                         NSError *err = nil;
  3915.                         if (![self createSockets:&err])
  3916.                         {
  3917.                                 [self closeWithError:err];
  3918.                                 return;
  3919.                         }
  3920.                 }
  3921.                
  3922.                 while ([sendQueue count] > 0)
  3923.                 {
  3924.                         // Dequeue the next object in the queue
  3925.                         currentSend = [sendQueue objectAtIndex:0];
  3926.                         [sendQueue removeObjectAtIndex:0];
  3927.                        
  3928.                         if ([currentSend isKindOfClass:[GCDAsyncUdpSpecialPacket class]])
  3929.                         {
  3930.                                 [self maybeConnect];
  3931.                                
  3932.                                 return; // The maybeConnect method, if it connects, will invoke this method again
  3933.                         }
  3934.                         else if (currentSend->resolveError)
  3935.                         {
  3936.                                 // Notify delegate
  3937.                                 [self notifyDidNotSendDataWithTag:currentSend->tag dueToError:currentSend->resolveError];
  3938.                                
  3939.                                 // Clear currentSend
  3940.                                 currentSend = nil;
  3941.                                
  3942.                                 continue;
  3943.                         }
  3944.                         else
  3945.                         {
  3946.                                 // Start preprocessing checks on the send packet
  3947.                                 [self doPreSend];
  3948.                                
  3949.                                 break;
  3950.                         }
  3951.                 }
  3952.                
  3953.                 if ((currentSend == nil) && (flags & kCloseAfterSends))
  3954.                 {
  3955.                         [self closeWithError:nil];
  3956.                 }
  3957.         }
  3958. }
  3959.  
  3960. /**
  3961.  * This method is called after a sendPacket has been dequeued.
  3962.  * It performs various preprocessing checks on the packet,
  3963.  * and queries the sendFilter (if set) to determine if the packet can be sent.
  3964.  *
  3965.  * If the packet passes all checks, it will be passed on to the doSend method.
  3966. **/
  3967. - (void)doPreSend
  3968. {
  3969.         LogTrace();
  3970.        
  3971.         //
  3972.         // 1. Check for problems with send packet
  3973.         //
  3974.        
  3975.         BOOL waitingForResolve = NO;
  3976.         NSError *error = nil;
  3977.        
  3978.         if (flags & kDidConnect)
  3979.         {
  3980.                 // Connected socket
  3981.                
  3982.                 if (currentSend->resolveInProgress || currentSend->resolvedAddresses || currentSend->resolveError)
  3983.                 {
  3984.                         NSString *msg = @"Cannot specify destination of packet for connected socket";
  3985.                         error = [self badConfigError:msg];
  3986.                 }
  3987.                 else
  3988.                 {
  3989.                         currentSend->address = cachedConnectedAddress;
  3990.                         currentSend->addressFamily = cachedConnectedFamily;
  3991.                 }
  3992.         }
  3993.         else
  3994.         {
  3995.                 // Non-Connected socket
  3996.                
  3997.                 if (currentSend->resolveInProgress)
  3998.                 {
  3999.                         // We're waiting for the packet's destination to be resolved.
  4000.                         waitingForResolve = YES;
  4001.                 }
  4002.                 else if (currentSend->resolveError)
  4003.                 {
  4004.                         error = currentSend->resolveError;
  4005.                 }
  4006.                 else if (currentSend->address == nil)
  4007.                 {
  4008.                         if (currentSend->resolvedAddresses == nil)
  4009.                         {
  4010.                                 NSString *msg = @"You must specify destination of packet for a non-connected socket";
  4011.                                 error = [self badConfigError:msg];
  4012.                         }
  4013.                         else
  4014.                         {
  4015.                                 // Pick the proper address to use (out of possibly several resolved addresses)
  4016.                                
  4017.                                 NSData *address = nil;
  4018.                                 int addressFamily = AF_UNSPEC;
  4019.                                
  4020.                                 addressFamily = [self getAddress:&address error:&error fromAddresses:currentSend->resolvedAddresses];
  4021.                                
  4022.                                 currentSend->address = address;
  4023.                                 currentSend->addressFamily = addressFamily;
  4024.                         }
  4025.                 }
  4026.         }
  4027.        
  4028.         if (waitingForResolve)
  4029.         {
  4030.                 // We're waiting for the packet's destination to be resolved.
  4031.                
  4032.                 LogVerbose(@"currentSend - waiting for address resolve");
  4033.                
  4034.                 if (flags & kSock4CanAcceptBytes) {
  4035.                         [self suspendSend4Source];
  4036.                 }
  4037.                 if (flags & kSock6CanAcceptBytes) {
  4038.                         [self suspendSend6Source];
  4039.                 }
  4040.                
  4041.                 return;
  4042.         }
  4043.        
  4044.         if (error)
  4045.         {
  4046.                 // Unable to send packet due to some error.
  4047.                 // Notify delegate and move on.
  4048.                
  4049.                 [self notifyDidNotSendDataWithTag:currentSend->tag dueToError:error];
  4050.                 [self endCurrentSend];
  4051.                 [self maybeDequeueSend];
  4052.                
  4053.                 return;
  4054.         }
  4055.        
  4056.         //
  4057.         // 2. Query sendFilter (if applicable)
  4058.         //
  4059.        
  4060.         if (sendFilterBlock && sendFilterQueue)
  4061.         {
  4062.                 // Query sendFilter
  4063.                
  4064.                 if (sendFilterAsync)
  4065.                 {
  4066.                         // Scenario 1 of 3 - Need to asynchronously query sendFilter
  4067.                        
  4068.                         currentSend->filterInProgress = YES;
  4069.                         GCDAsyncUdpSendPacket *sendPacket = currentSend;
  4070.                        
  4071.                         dispatch_async(sendFilterQueue, ^{ @autoreleasepool {
  4072.                                
  4073.                 BOOL allowed = self->sendFilterBlock(sendPacket->buffer, sendPacket->address, sendPacket->tag);
  4074.                                
  4075.                 dispatch_async(self->socketQueue, ^{ @autoreleasepool {
  4076.                                        
  4077.                                         sendPacket->filterInProgress = NO;
  4078.                     if (sendPacket == self->currentSend)
  4079.                                         {
  4080.                                                 if (allowed)
  4081.                                                 {
  4082.                                                         [self doSend];
  4083.                                                 }
  4084.                                                 else
  4085.                                                 {
  4086.                                                         LogVerbose(@"currentSend - silently dropped by sendFilter");
  4087.                                                        
  4088.                             [self notifyDidSendDataWithTag:self->currentSend->tag];
  4089.                                                         [self endCurrentSend];
  4090.                                                         [self maybeDequeueSend];
  4091.                                                 }
  4092.                                         }
  4093.                                 }});
  4094.                         }});
  4095.                 }
  4096.                 else
  4097.                 {
  4098.                         // Scenario 2 of 3 - Need to synchronously query sendFilter
  4099.                        
  4100.                         __block BOOL allowed = YES;
  4101.                        
  4102.                         dispatch_sync(sendFilterQueue, ^{ @autoreleasepool {
  4103.                                
  4104.                 allowed = self->sendFilterBlock(self->currentSend->buffer, self->currentSend->address, self->currentSend->tag);
  4105.                         }});
  4106.                        
  4107.                         if (allowed)
  4108.                         {
  4109.                                 [self doSend];
  4110.                         }
  4111.                         else
  4112.                         {
  4113.                                 LogVerbose(@"currentSend - silently dropped by sendFilter");
  4114.                                
  4115.                                 [self notifyDidSendDataWithTag:currentSend->tag];
  4116.                                 [self endCurrentSend];
  4117.                                 [self maybeDequeueSend];
  4118.                         }
  4119.                 }
  4120.         }
  4121.         else // if (!sendFilterBlock || !sendFilterQueue)
  4122.         {
  4123.                 // Scenario 3 of 3 - No sendFilter. Just go straight into sending.
  4124.                
  4125.                 [self doSend];
  4126.         }
  4127. }
  4128.  
  4129. /**
  4130.  * This method performs the actual sending of data in the currentSend packet.
  4131.  * It should only be called if the
  4132. **/
  4133. - (void)doSend
  4134. {
  4135.         LogTrace();
  4136.        
  4137.         NSAssert(currentSend != nil, @"Invalid logic");
  4138.        
  4139.         // Perform the actual send
  4140.        
  4141.         ssize_t result = 0;
  4142.        
  4143.         if (flags & kDidConnect)
  4144.         {
  4145.                 // Connected socket
  4146.                
  4147.                 const void *buffer = [currentSend->buffer bytes];
  4148.                 size_t length = (size_t)[currentSend->buffer length];
  4149.                
  4150.                 if (currentSend->addressFamily == AF_INET)
  4151.                 {
  4152.                         result = send(socket4FD, buffer, length, 0);
  4153.                         LogVerbose(@"send(socket4FD) = %d", result);
  4154.                 }
  4155.                 else
  4156.                 {
  4157.                         result = send(socket6FD, buffer, length, 0);
  4158.                         LogVerbose(@"send(socket6FD) = %d", result);
  4159.                 }
  4160.         }
  4161.         else
  4162.         {
  4163.                 // Non-Connected socket
  4164.                
  4165.                 const void *buffer = [currentSend->buffer bytes];
  4166.                 size_t length = (size_t)[currentSend->buffer length];
  4167.                
  4168.                 const void *dst  = [currentSend->address bytes];
  4169.                 socklen_t dstSize = (socklen_t)[currentSend->address length];
  4170.                
  4171.                 if (currentSend->addressFamily == AF_INET)
  4172.                 {
  4173.                         result = sendto(socket4FD, buffer, length, 0, dst, dstSize);
  4174.                         LogVerbose(@"sendto(socket4FD) = %d", result);
  4175.                 }
  4176.                 else
  4177.                 {
  4178.                         result = sendto(socket6FD, buffer, length, 0, dst, dstSize);
  4179.                         LogVerbose(@"sendto(socket6FD) = %d", result);
  4180.                 }
  4181.         }
  4182.        
  4183.         // If the socket wasn't bound before, it is now
  4184.        
  4185.         if ((flags & kDidBind) == 0)
  4186.         {
  4187.                 flags |= kDidBind;
  4188.         }
  4189.        
  4190.         // Check the results.
  4191.         //
  4192.         // From the send() & sendto() manpage:
  4193.         //
  4194.         // Upon successful completion, the number of bytes which were sent is returned.
  4195.         // Otherwise, -1 is returned and the global variable errno is set to indicate the error.
  4196.        
  4197.         BOOL waitingForSocket = NO;
  4198.         NSError *socketError = nil;
  4199.        
  4200.         if (result == 0)
  4201.         {
  4202.                 waitingForSocket = YES;
  4203.         }
  4204.         else if (result < 0)
  4205.         {
  4206.                 if (errno == EAGAIN)
  4207.                         waitingForSocket = YES;
  4208.                 else
  4209.                         socketError = [self errnoErrorWithReason:@"Error in send() function."];
  4210.         }
  4211.        
  4212.         if (waitingForSocket)
  4213.         {
  4214.                 // Not enough room in the underlying OS socket send buffer.
  4215.                 // Wait for a notification of available space.
  4216.                
  4217.                 LogVerbose(@"currentSend - waiting for socket");
  4218.                
  4219.                 if (!(flags & kSock4CanAcceptBytes)) {
  4220.                         [self resumeSend4Source];
  4221.                 }
  4222.                 if (!(flags & kSock6CanAcceptBytes)) {
  4223.                         [self resumeSend6Source];
  4224.                 }
  4225.                
  4226.                 if ((sendTimer == NULL) && (currentSend->timeout >= 0.0))
  4227.                 {
  4228.                         // Unable to send packet right away.
  4229.                         // Start timer to timeout the send operation.
  4230.                        
  4231.                         [self setupSendTimerWithTimeout:currentSend->timeout];
  4232.                 }
  4233.         }
  4234.         else if (socketError)
  4235.         {
  4236.                 [self closeWithError:socketError];
  4237.         }
  4238.         else // done
  4239.         {
  4240.                 [self notifyDidSendDataWithTag:currentSend->tag];
  4241.                 [self endCurrentSend];
  4242.                 [self maybeDequeueSend];
  4243.         }
  4244. }
  4245.  
  4246. /**
  4247.  * Releases all resources associated with the currentSend.
  4248. **/
  4249. - (void)endCurrentSend
  4250. {
  4251.         if (sendTimer)
  4252.         {
  4253.                 dispatch_source_cancel(sendTimer);
  4254.                 #if !OS_OBJECT_USE_OBJC
  4255.                 dispatch_release(sendTimer);
  4256.                 #endif
  4257.                 sendTimer = NULL;
  4258.         }
  4259.        
  4260.         currentSend = nil;
  4261. }
  4262.  
  4263. /**
  4264.  * Performs the operations to timeout the current send operation, and move on.
  4265. **/
  4266. - (void)doSendTimeout
  4267. {
  4268.         LogTrace();
  4269.        
  4270.         [self notifyDidNotSendDataWithTag:currentSend->tag dueToError:[self sendTimeoutError]];
  4271.         [self endCurrentSend];
  4272.         [self maybeDequeueSend];
  4273. }
  4274.  
  4275. /**
  4276.  * Sets up a timer that fires to timeout the current send operation.
  4277.  * This method should only be called once per send packet.
  4278. **/
  4279. - (void)setupSendTimerWithTimeout:(NSTimeInterval)timeout
  4280. {
  4281.         NSAssert(sendTimer == NULL, @"Invalid logic");
  4282.         NSAssert(timeout >= 0.0, @"Invalid logic");
  4283.        
  4284.         LogTrace();
  4285.        
  4286.         sendTimer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, socketQueue);
  4287.        
  4288.         dispatch_source_set_event_handler(sendTimer, ^{ @autoreleasepool {
  4289.                
  4290.                 [self doSendTimeout];
  4291.         }});
  4292.        
  4293.         dispatch_time_t tt = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(timeout * NSEC_PER_SEC));
  4294.        
  4295.         dispatch_source_set_timer(sendTimer, tt, DISPATCH_TIME_FOREVER, 0);
  4296.         dispatch_resume(sendTimer);
  4297. }
  4298.  
  4299. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  4300. #pragma mark Receiving
  4301. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  4302.  
  4303. - (BOOL)receiveOnce:(NSError **)errPtr
  4304. {
  4305.         LogTrace();
  4306.        
  4307.         __block BOOL result = NO;
  4308.         __block NSError *err = nil;
  4309.        
  4310.         dispatch_block_t block = ^{
  4311.                
  4312.         if ((self->flags & kReceiveOnce) == 0)
  4313.                 {
  4314.             if ((self->flags & kDidCreateSockets) == 0)
  4315.                         {
  4316.                                 NSString *msg = @"Must bind socket before you can receive data. "
  4317.                                 @"You can do this explicitly via bind, or implicitly via connect or by sending data.";
  4318.                                
  4319.                                 err = [self badConfigError:msg];
  4320.                                 return_from_block;
  4321.                         }
  4322.                        
  4323.             self->flags |=  kReceiveOnce;       // Enable
  4324.             self->flags &= ~kReceiveContinuous; // Disable
  4325.                        
  4326.             dispatch_async(self->socketQueue, ^{ @autoreleasepool {
  4327.                                
  4328.                                 [self doReceive];
  4329.                         }});
  4330.                 }
  4331.                
  4332.                 result = YES;
  4333.         };
  4334.        
  4335.         if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
  4336.                 block();
  4337.         else
  4338.                 dispatch_sync(socketQueue, block);
  4339.        
  4340.         if (err)
  4341.                 LogError(@"Error in beginReceiving: %@", err);
  4342.        
  4343.         if (errPtr)
  4344.                 *errPtr = err;
  4345.        
  4346.         return result;
  4347. }
  4348.  
  4349. - (BOOL)beginReceiving:(NSError **)errPtr
  4350. {
  4351.         LogTrace();
  4352.        
  4353.         __block BOOL result = NO;
  4354.         __block NSError *err = nil;
  4355.        
  4356.         dispatch_block_t block = ^{
  4357.                
  4358.         if ((self->flags & kReceiveContinuous) == 0)
  4359.                 {
  4360.             if ((self->flags & kDidCreateSockets) == 0)
  4361.                         {
  4362.                                 NSString *msg = @"Must bind socket before you can receive data. "
  4363.                                                                 @"You can do this explicitly via bind, or implicitly via connect or by sending data.";
  4364.                                
  4365.                                 err = [self badConfigError:msg];
  4366.                                 return_from_block;
  4367.                         }
  4368.                        
  4369.             self->flags |= kReceiveContinuous; // Enable
  4370.             self->flags &= ~kReceiveOnce;      // Disable
  4371.                        
  4372.             dispatch_async(self->socketQueue, ^{ @autoreleasepool {
  4373.                                
  4374.                                 [self doReceive];
  4375.                         }});
  4376.                 }
  4377.                
  4378.                 result = YES;
  4379.         };
  4380.        
  4381.         if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
  4382.                 block();
  4383.         else
  4384.                 dispatch_sync(socketQueue, block);
  4385.        
  4386.         if (err)
  4387.                 LogError(@"Error in beginReceiving: %@", err);
  4388.        
  4389.         if (errPtr)
  4390.                 *errPtr = err;
  4391.        
  4392.         return result;
  4393. }
  4394.  
  4395. - (void)pauseReceiving
  4396. {
  4397.         LogTrace();
  4398.        
  4399.         dispatch_block_t block = ^{
  4400.                
  4401.         self->flags &= ~kReceiveOnce;       // Disable
  4402.         self->flags &= ~kReceiveContinuous; // Disable
  4403.                
  4404.         if (self->socket4FDBytesAvailable > 0) {
  4405.                         [self suspendReceive4Source];
  4406.                 }
  4407.         if (self->socket6FDBytesAvailable > 0) {
  4408.                         [self suspendReceive6Source];
  4409.                 }
  4410.         };
  4411.        
  4412.         if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
  4413.                 block();
  4414.         else
  4415.                 dispatch_async(socketQueue, block);
  4416. }
  4417.  
  4418. - (void)setReceiveFilter:(GCDAsyncUdpSocketReceiveFilterBlock)filterBlock withQueue:(dispatch_queue_t)filterQueue
  4419. {
  4420.         [self setReceiveFilter:filterBlock withQueue:filterQueue isAsynchronous:YES];
  4421. }
  4422.  
  4423. - (void)setReceiveFilter:(GCDAsyncUdpSocketReceiveFilterBlock)filterBlock
  4424.                withQueue:(dispatch_queue_t)filterQueue
  4425.           isAsynchronous:(BOOL)isAsynchronous
  4426. {
  4427.         GCDAsyncUdpSocketReceiveFilterBlock newFilterBlock = NULL;
  4428.         dispatch_queue_t newFilterQueue = NULL;
  4429.        
  4430.         if (filterBlock)
  4431.         {
  4432.                 NSAssert(filterQueue, @"Must provide a dispatch_queue in which to run the filter block.");
  4433.                
  4434.                 newFilterBlock = [filterBlock copy];
  4435.                 newFilterQueue = filterQueue;
  4436.                 #if !OS_OBJECT_USE_OBJC
  4437.                 dispatch_retain(newFilterQueue);
  4438.                 #endif
  4439.         }
  4440.        
  4441.         dispatch_block_t block = ^{
  4442.                
  4443.                 #if !OS_OBJECT_USE_OBJC
  4444.         if (self->receiveFilterQueue) dispatch_release(self->receiveFilterQueue);
  4445.                 #endif
  4446.                
  4447.         self->receiveFilterBlock = newFilterBlock;
  4448.         self->receiveFilterQueue = newFilterQueue;
  4449.         self->receiveFilterAsync = isAsynchronous;
  4450.         };
  4451.        
  4452.         if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
  4453.                 block();
  4454.         else
  4455.                 dispatch_async(socketQueue, block);
  4456. }
  4457.  
  4458. - (void)doReceive
  4459. {
  4460.         LogTrace();
  4461.        
  4462.         if ((flags & (kReceiveOnce | kReceiveContinuous)) == 0)
  4463.         {
  4464.                 LogVerbose(@"Receiving is paused...");
  4465.                
  4466.                 if (socket4FDBytesAvailable > 0) {
  4467.                         [self suspendReceive4Source];
  4468.                 }
  4469.                 if (socket6FDBytesAvailable > 0) {
  4470.                         [self suspendReceive6Source];
  4471.                 }
  4472.                
  4473.                 return;
  4474.         }
  4475.        
  4476.         if ((flags & kReceiveOnce) && (pendingFilterOperations > 0))
  4477.         {
  4478.                 LogVerbose(@"Receiving is temporarily paused (pending filter operations)...");
  4479.                
  4480.                 if (socket4FDBytesAvailable > 0) {
  4481.                         [self suspendReceive4Source];
  4482.                 }
  4483.                 if (socket6FDBytesAvailable > 0) {
  4484.                         [self suspendReceive6Source];
  4485.                 }
  4486.                
  4487.                 return;
  4488.         }
  4489.        
  4490.         if ((socket4FDBytesAvailable == 0) && (socket6FDBytesAvailable == 0))
  4491.         {
  4492.                 LogVerbose(@"No data available to receive...");
  4493.                
  4494.                 if (socket4FDBytesAvailable == 0) {
  4495.                         [self resumeReceive4Source];
  4496.                 }
  4497.                 if (socket6FDBytesAvailable == 0) {
  4498.                         [self resumeReceive6Source];
  4499.                 }
  4500.                
  4501.                 return;
  4502.         }
  4503.        
  4504.         // Figure out if we should receive on socket4 or socket6
  4505.        
  4506.         BOOL doReceive4;
  4507.        
  4508.         if (flags & kDidConnect)
  4509.         {
  4510.                 // Connected socket
  4511.                
  4512.                 doReceive4 = (socket4FD != SOCKET_NULL);
  4513.         }
  4514.         else
  4515.         {
  4516.                 // Non-Connected socket
  4517.                
  4518.                 if (socket4FDBytesAvailable > 0)
  4519.                 {
  4520.                         if (socket6FDBytesAvailable > 0)
  4521.                         {
  4522.                                 // Bytes available on socket4 & socket6
  4523.                                
  4524.                                 doReceive4 = (flags & kFlipFlop) ? YES : NO;
  4525.                                
  4526.                                 flags ^= kFlipFlop; // flags = flags xor kFlipFlop; (toggle flip flop bit)
  4527.                         }
  4528.                         else {
  4529.                                 // Bytes available on socket4, but not socket6
  4530.                                 doReceive4 = YES;
  4531.                         }
  4532.                 }
  4533.                 else {
  4534.                         // Bytes available on socket6, but not socket4
  4535.                         doReceive4 = NO;
  4536.                 }
  4537.         }
  4538.        
  4539.         // Perform socket IO
  4540.        
  4541.         ssize_t result = 0;
  4542.        
  4543.         NSData *data = nil;
  4544.         NSData *addr4 = nil;
  4545.         NSData *addr6 = nil;
  4546.        
  4547.         if (doReceive4)
  4548.         {
  4549.                 NSAssert(socket4FDBytesAvailable > 0, @"Invalid logic");
  4550.                 LogVerbose(@"Receiving on IPv4");
  4551.                
  4552.                 struct sockaddr_in sockaddr4;
  4553.                 socklen_t sockaddr4len = sizeof(sockaddr4);
  4554.                
  4555.                 // #222: GCD does not necessarily return the size of an entire UDP packet
  4556.                 // from dispatch_source_get_data(), so we must use the maximum packet size.
  4557.                 size_t bufSize = max4ReceiveSize;
  4558.                 void *buf = malloc(bufSize);
  4559.                
  4560.                 result = recvfrom(socket4FD, buf, bufSize, 0, (struct sockaddr *)&sockaddr4, &sockaddr4len);
  4561.                 LogVerbose(@"recvfrom(socket4FD) = %i", (int)result);
  4562.                
  4563.                 if (result > 0)
  4564.                 {
  4565.                         if ((size_t)result >= socket4FDBytesAvailable)
  4566.                                 socket4FDBytesAvailable = 0;
  4567.                         else
  4568.                                 socket4FDBytesAvailable -= result;
  4569.                        
  4570.                         if ((size_t)result != bufSize) {
  4571.                                 buf = realloc(buf, result);
  4572.                         }
  4573.                        
  4574.                         data = [NSData dataWithBytesNoCopy:buf length:result freeWhenDone:YES];
  4575.                         addr4 = [NSData dataWithBytes:&sockaddr4 length:sockaddr4len];
  4576.                 }
  4577.                 else
  4578.                 {
  4579.                         LogVerbose(@"recvfrom(socket4FD) = %@", [self errnoError]);
  4580.                         socket4FDBytesAvailable = 0;
  4581.                         free(buf);
  4582.                 }
  4583.         }
  4584.         else
  4585.         {
  4586.                 NSAssert(socket6FDBytesAvailable > 0, @"Invalid logic");
  4587.                 LogVerbose(@"Receiving on IPv6");
  4588.                
  4589.                 struct sockaddr_in6 sockaddr6;
  4590.                 socklen_t sockaddr6len = sizeof(sockaddr6);
  4591.                
  4592.                 // #222: GCD does not necessarily return the size of an entire UDP packet
  4593.                 // from dispatch_source_get_data(), so we must use the maximum packet size.
  4594.                 size_t bufSize = max6ReceiveSize;
  4595.                 void *buf = malloc(bufSize);
  4596.                
  4597.                 result = recvfrom(socket6FD, buf, bufSize, 0, (struct sockaddr *)&sockaddr6, &sockaddr6len);
  4598.                 LogVerbose(@"recvfrom(socket6FD) -> %i", (int)result);
  4599.                
  4600.                 if (result > 0)
  4601.                 {
  4602.                         if ((size_t)result >= socket6FDBytesAvailable)
  4603.                                 socket6FDBytesAvailable = 0;
  4604.                         else
  4605.                                 socket6FDBytesAvailable -= result;
  4606.                        
  4607.                         if ((size_t)result != bufSize) {
  4608.                                 buf = realloc(buf, result);
  4609.                         }
  4610.                
  4611.                         data = [NSData dataWithBytesNoCopy:buf length:result freeWhenDone:YES];
  4612.                         addr6 = [NSData dataWithBytes:&sockaddr6 length:sockaddr6len];
  4613.                 }
  4614.                 else
  4615.                 {
  4616.                         LogVerbose(@"recvfrom(socket6FD) = %@", [self errnoError]);
  4617.                         socket6FDBytesAvailable = 0;
  4618.                         free(buf);
  4619.                 }
  4620.         }
  4621.        
  4622.        
  4623.         BOOL waitingForSocket = NO;
  4624.         BOOL notifiedDelegate = NO;
  4625.         BOOL ignored = NO;
  4626.        
  4627.         NSError *socketError = nil;
  4628.        
  4629.         if (result == 0)
  4630.         {
  4631.                 waitingForSocket = YES;
  4632.         }
  4633.         else if (result < 0)
  4634.         {
  4635.                 if (errno == EAGAIN)
  4636.                         waitingForSocket = YES;
  4637.                 else
  4638.                         socketError = [self errnoErrorWithReason:@"Error in recvfrom() function"];
  4639.         }
  4640.         else
  4641.         {
  4642.                 if (flags & kDidConnect)
  4643.                 {
  4644.                         if (addr4 && ![self isConnectedToAddress4:addr4])
  4645.                                 ignored = YES;
  4646.                         if (addr6 && ![self isConnectedToAddress6:addr6])
  4647.                                 ignored = YES;
  4648.                 }
  4649.                
  4650.                 NSData *addr = (addr4 != nil) ? addr4 : addr6;
  4651.                
  4652.                 if (!ignored)
  4653.                 {
  4654.                         if (receiveFilterBlock && receiveFilterQueue)
  4655.                         {
  4656.                                 // Run data through filter, and if approved, notify delegate
  4657.                                
  4658.                                 __block id filterContext = nil;
  4659.                                 __block BOOL allowed = NO;
  4660.                                
  4661.                                 if (receiveFilterAsync)
  4662.                                 {
  4663.                                         pendingFilterOperations++;
  4664.                                         dispatch_async(receiveFilterQueue, ^{ @autoreleasepool {
  4665.                                                
  4666.                         allowed = self->receiveFilterBlock(data, addr, &filterContext);
  4667.                                                
  4668.                                                 // Transition back to socketQueue to get the current delegate / delegateQueue
  4669.                         dispatch_async(self->socketQueue, ^{ @autoreleasepool {
  4670.                                                        
  4671.                             self->pendingFilterOperations--;
  4672.                                                        
  4673.                                                         if (allowed)
  4674.                                                         {
  4675.                                                                 [self notifyDidReceiveData:data fromAddress:addr withFilterContext:filterContext];
  4676.                                                         }
  4677.                                                         else
  4678.                                                         {
  4679.                                                                 LogVerbose(@"received packet silently dropped by receiveFilter");
  4680.                                                         }
  4681.                                                        
  4682.                             if (self->flags & kReceiveOnce)
  4683.                                                         {
  4684.                                                                 if (allowed)
  4685.                                                                 {
  4686.                                                                         // The delegate has been notified,
  4687.                                                                         // so our receive once operation has completed.
  4688.                                     self->flags &= ~kReceiveOnce;
  4689.                                                                 }
  4690.                                 else if (self->pendingFilterOperations == 0)
  4691.                                                                 {
  4692.                                                                         // All pending filter operations have completed,
  4693.                                                                         // and none were allowed through.
  4694.                                                                         // Our receive once operation hasn't completed yet.
  4695.                                                                         [self doReceive];
  4696.                                                                 }
  4697.                                                         }
  4698.                                                 }});
  4699.                                         }});
  4700.                                 }
  4701.                                 else // if (!receiveFilterAsync)
  4702.                                 {
  4703.                                         dispatch_sync(receiveFilterQueue, ^{ @autoreleasepool {
  4704.                                                
  4705.                         allowed = self->receiveFilterBlock(data, addr, &filterContext);
  4706.                                         }});
  4707.                                        
  4708.                                         if (allowed)
  4709.                                         {
  4710.                                                 [self notifyDidReceiveData:data fromAddress:addr withFilterContext:filterContext];
  4711.                                                 notifiedDelegate = YES;
  4712.                                         }
  4713.                                         else
  4714.                                         {
  4715.                                                 LogVerbose(@"received packet silently dropped by receiveFilter");
  4716.                                                 ignored = YES;
  4717.                                         }
  4718.                                 }
  4719.                         }
  4720.                         else // if (!receiveFilterBlock || !receiveFilterQueue)
  4721.                         {
  4722.                                 [self notifyDidReceiveData:data fromAddress:addr withFilterContext:nil];
  4723.                                 notifiedDelegate = YES;
  4724.                         }
  4725.                 }
  4726.         }
  4727.        
  4728.         if (waitingForSocket)
  4729.         {
  4730.                 // Wait for a notification of available data.
  4731.                
  4732.                 if (socket4FDBytesAvailable == 0) {
  4733.                         [self resumeReceive4Source];
  4734.                 }
  4735.                 if (socket6FDBytesAvailable == 0) {
  4736.                         [self resumeReceive6Source];
  4737.                 }
  4738.         }
  4739.         else if (socketError)
  4740.         {
  4741.                 [self closeWithError:socketError];
  4742.         }
  4743.         else
  4744.         {
  4745.                 if (flags & kReceiveContinuous)
  4746.                 {
  4747.                         // Continuous receive mode
  4748.                         [self doReceive];
  4749.                 }
  4750.                 else
  4751.                 {
  4752.                         // One-at-a-time receive mode
  4753.                         if (notifiedDelegate)
  4754.                         {
  4755.                                 // The delegate has been notified (no set filter).
  4756.                                 // So our receive once operation has completed.
  4757.                                 flags &= ~kReceiveOnce;
  4758.                         }
  4759.                         else if (ignored)
  4760.                         {
  4761.                                 [self doReceive];
  4762.                         }
  4763.                         else
  4764.                         {
  4765.                                 // Waiting on asynchronous receive filter...
  4766.                         }
  4767.                 }
  4768.         }
  4769. }
  4770.  
  4771. - (void)doReceiveEOF
  4772. {
  4773.         LogTrace();
  4774.        
  4775.         [self closeWithError:[self socketClosedError]];
  4776. }
  4777.  
  4778. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  4779. #pragma mark Closing
  4780. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  4781.  
  4782. - (void)closeWithError:(NSError *)error
  4783. {
  4784.         LogVerbose(@"closeWithError: %@", error);
  4785.        
  4786.         NSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @"Must be dispatched on socketQueue");
  4787.        
  4788.         if (currentSend) [self endCurrentSend];
  4789.        
  4790.         [sendQueue removeAllObjects];
  4791.        
  4792.         // If a socket has been created, we should notify the delegate.
  4793.         BOOL shouldCallDelegate = (flags & kDidCreateSockets) ? YES : NO;
  4794.        
  4795.         // Close all sockets, send/receive sources, cfstreams, etc
  4796. #if TARGET_OS_IPHONE
  4797.         [self removeStreamsFromRunLoop];
  4798.         [self closeReadAndWriteStreams];
  4799. #endif
  4800.         [self closeSockets];
  4801.        
  4802.         // Clear all flags (config remains as is)
  4803.         flags = 0;
  4804.        
  4805.         if (shouldCallDelegate)
  4806.         {
  4807.                 [self notifyDidCloseWithError:error];
  4808.         }
  4809. }
  4810.  
  4811. - (void)close
  4812. {
  4813.         LogTrace();
  4814.        
  4815.         dispatch_block_t block = ^{ @autoreleasepool {
  4816.                
  4817.                 [self closeWithError:nil];
  4818.         }};
  4819.        
  4820.         if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
  4821.                 block();
  4822.         else
  4823.                 dispatch_sync(socketQueue, block);
  4824. }
  4825.  
  4826. - (void)closeAfterSending
  4827. {
  4828.         LogTrace();
  4829.        
  4830.         dispatch_block_t block = ^{ @autoreleasepool {
  4831.                
  4832.         self->flags |= kCloseAfterSends;
  4833.                
  4834.         if (self->currentSend == nil && [self->sendQueue count] == 0)
  4835.                 {
  4836.                         [self closeWithError:nil];
  4837.                 }
  4838.         }};
  4839.        
  4840.         if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
  4841.                 block();
  4842.         else
  4843.                 dispatch_async(socketQueue, block);
  4844. }
  4845.  
  4846. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  4847. #pragma mark CFStream
  4848. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  4849.  
  4850. #if TARGET_OS_IPHONE
  4851.  
  4852. static NSThread *listenerThread;
  4853.  
  4854. + (void)ignore:(id)_
  4855. {}
  4856.  
  4857. + (void)startListenerThreadIfNeeded
  4858. {
  4859.         static dispatch_once_t predicate;
  4860.         dispatch_once(&predicate, ^{
  4861.                
  4862.                 listenerThread = [[NSThread alloc] initWithTarget:self
  4863.                                                          selector:@selector(listenerThread:)
  4864.                                                            object:nil];
  4865.                 [listenerThread start];
  4866.         });
  4867. }
  4868.  
  4869. + (void)listenerThread:(id)unused
  4870. {
  4871.         @autoreleasepool {
  4872.        
  4873.                 [[NSThread currentThread] setName:GCDAsyncUdpSocketThreadName];
  4874.                
  4875.                 LogInfo(@"ListenerThread: Started");
  4876.                
  4877.                 // We can't run the run loop unless it has an associated input source or a timer.
  4878.                 // So we'll just create a timer that will never fire - unless the server runs for a decades.
  4879.                 [NSTimer scheduledTimerWithTimeInterval:[[NSDate distantFuture] timeIntervalSinceNow]
  4880.                                                  target:self
  4881.                                                selector:@selector(ignore:)
  4882.                                                userInfo:nil
  4883.                                                 repeats:YES];
  4884.                
  4885.                 [[NSRunLoop currentRunLoop] run];
  4886.                
  4887.                 LogInfo(@"ListenerThread: Stopped");
  4888.         }
  4889. }
  4890.  
  4891. + (void)addStreamListener:(GCDAsyncUdpSocket *)asyncUdpSocket
  4892. {
  4893.         LogTrace();
  4894.         NSAssert([NSThread currentThread] == listenerThread, @"Invoked on wrong thread");
  4895.        
  4896.         CFRunLoopRef runLoop = CFRunLoopGetCurrent();
  4897.        
  4898.         if (asyncUdpSocket->readStream4)
  4899.                 CFReadStreamScheduleWithRunLoop(asyncUdpSocket->readStream4, runLoop, kCFRunLoopDefaultMode);
  4900.        
  4901.         if (asyncUdpSocket->readStream6)
  4902.                 CFReadStreamScheduleWithRunLoop(asyncUdpSocket->readStream6, runLoop, kCFRunLoopDefaultMode);
  4903.        
  4904.         if (asyncUdpSocket->writeStream4)
  4905.                 CFWriteStreamScheduleWithRunLoop(asyncUdpSocket->writeStream4, runLoop, kCFRunLoopDefaultMode);
  4906.        
  4907.         if (asyncUdpSocket->writeStream6)
  4908.                 CFWriteStreamScheduleWithRunLoop(asyncUdpSocket->writeStream6, runLoop, kCFRunLoopDefaultMode);
  4909. }
  4910.  
  4911. + (void)removeStreamListener:(GCDAsyncUdpSocket *)asyncUdpSocket
  4912. {
  4913.         LogTrace();
  4914.         NSAssert([NSThread currentThread] == listenerThread, @"Invoked on wrong thread");
  4915.        
  4916.         CFRunLoopRef runLoop = CFRunLoopGetCurrent();
  4917.        
  4918.         if (asyncUdpSocket->readStream4)
  4919.                 CFReadStreamUnscheduleFromRunLoop(asyncUdpSocket->readStream4, runLoop, kCFRunLoopDefaultMode);
  4920.        
  4921.         if (asyncUdpSocket->readStream6)
  4922.                 CFReadStreamUnscheduleFromRunLoop(asyncUdpSocket->readStream6, runLoop, kCFRunLoopDefaultMode);
  4923.        
  4924.         if (asyncUdpSocket->writeStream4)
  4925.                 CFWriteStreamUnscheduleFromRunLoop(asyncUdpSocket->writeStream4, runLoop, kCFRunLoopDefaultMode);
  4926.        
  4927.         if (asyncUdpSocket->writeStream6)
  4928.                 CFWriteStreamUnscheduleFromRunLoop(asyncUdpSocket->writeStream6, runLoop, kCFRunLoopDefaultMode);
  4929. }
  4930.  
  4931. static void CFReadStreamCallback(CFReadStreamRef stream, CFStreamEventType type, void *pInfo)
  4932. {
  4933.         @autoreleasepool {
  4934.                 GCDAsyncUdpSocket *asyncUdpSocket = (__bridge GCDAsyncUdpSocket *)pInfo;
  4935.        
  4936.                 switch(type)
  4937.                 {
  4938.                         case kCFStreamEventOpenCompleted:
  4939.                         {
  4940.                                 LogCVerbose(@"CFReadStreamCallback - Open");
  4941.                                 break;
  4942.                         }
  4943.                         case kCFStreamEventHasBytesAvailable:
  4944.                         {
  4945.                                 LogCVerbose(@"CFReadStreamCallback - HasBytesAvailable");
  4946.                                 break;
  4947.                         }
  4948.                         case kCFStreamEventErrorOccurred:
  4949.                         case kCFStreamEventEndEncountered:
  4950.                         {
  4951.                                 NSError *error = (__bridge_transfer NSError *)CFReadStreamCopyError(stream);
  4952.                                 if (error == nil && type == kCFStreamEventEndEncountered)
  4953.                                 {
  4954.                                         error = [asyncUdpSocket socketClosedError];
  4955.                                 }
  4956.                                
  4957.                                 dispatch_async(asyncUdpSocket->socketQueue, ^{ @autoreleasepool {
  4958.                                        
  4959.                                         LogCVerbose(@"CFReadStreamCallback - %@",
  4960.                                                      (type == kCFStreamEventErrorOccurred) ? @"Error" : @"EndEncountered");
  4961.                                        
  4962.                                         if (stream != asyncUdpSocket->readStream4 &&
  4963.                                             stream != asyncUdpSocket->readStream6  )
  4964.                                         {
  4965.                                                 LogCVerbose(@"CFReadStreamCallback - Ignored");
  4966.                                                 return_from_block;
  4967.                                         }
  4968.                                        
  4969.                                         [asyncUdpSocket closeWithError:error];
  4970.                                        
  4971.                                 }});
  4972.                                
  4973.                                 break;
  4974.                         }
  4975.                         default:
  4976.                         {
  4977.                                 LogCError(@"CFReadStreamCallback - UnknownType: %i", (int)type);
  4978.                         }
  4979.                 }
  4980.         }
  4981. }
  4982.  
  4983. static void CFWriteStreamCallback(CFWriteStreamRef stream, CFStreamEventType type, void *pInfo)
  4984. {
  4985.         @autoreleasepool {
  4986.                 GCDAsyncUdpSocket *asyncUdpSocket = (__bridge GCDAsyncUdpSocket *)pInfo;
  4987.                
  4988.                 switch(type)
  4989.                 {
  4990.                         case kCFStreamEventOpenCompleted:
  4991.                         {
  4992.                                 LogCVerbose(@"CFWriteStreamCallback - Open");
  4993.                                 break;
  4994.                         }
  4995.                         case kCFStreamEventCanAcceptBytes:
  4996.                         {
  4997.                                 LogCVerbose(@"CFWriteStreamCallback - CanAcceptBytes");
  4998.                                 break;
  4999.                         }
  5000.                         case kCFStreamEventErrorOccurred:
  5001.                         case kCFStreamEventEndEncountered:
  5002.                         {
  5003.                                 NSError *error = (__bridge_transfer NSError *)CFWriteStreamCopyError(stream);
  5004.                                 if (error == nil && type == kCFStreamEventEndEncountered)
  5005.                                 {
  5006.                                         error = [asyncUdpSocket socketClosedError];
  5007.                                 }
  5008.                                
  5009.                                 dispatch_async(asyncUdpSocket->socketQueue, ^{ @autoreleasepool {
  5010.                                        
  5011.                                         LogCVerbose(@"CFWriteStreamCallback - %@",
  5012.                                                      (type == kCFStreamEventErrorOccurred) ? @"Error" : @"EndEncountered");
  5013.                                        
  5014.                                         if (stream != asyncUdpSocket->writeStream4 &&
  5015.                                             stream != asyncUdpSocket->writeStream6  )
  5016.                                         {
  5017.                                                 LogCVerbose(@"CFWriteStreamCallback - Ignored");
  5018.                                                 return_from_block;
  5019.                                         }
  5020.                                        
  5021.                                         [asyncUdpSocket closeWithError:error];
  5022.                                        
  5023.                                 }});
  5024.                                
  5025.                                 break;
  5026.                         }
  5027.                         default:
  5028.                         {
  5029.                                 LogCError(@"CFWriteStreamCallback - UnknownType: %i", (int)type);
  5030.                         }
  5031.                 }
  5032.         }
  5033. }
  5034.  
  5035. - (BOOL)createReadAndWriteStreams:(NSError **)errPtr
  5036. {
  5037.         LogTrace();
  5038.         NSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @"Must be dispatched on socketQueue");
  5039.        
  5040.         NSError *err = nil;
  5041.        
  5042.         if (readStream4 || writeStream4 || readStream6 || writeStream6)
  5043.         {
  5044.                 // Streams already created
  5045.                 return YES;
  5046.         }
  5047.        
  5048.         if (socket4FD == SOCKET_NULL && socket6FD == SOCKET_NULL)
  5049.         {
  5050.                 err = [self otherError:@"Cannot create streams without a file descriptor"];
  5051.                 goto Failed;
  5052.         }
  5053.        
  5054.         // Create streams
  5055.        
  5056.         LogVerbose(@"Creating read and write stream(s)...");
  5057.        
  5058.         if (socket4FD != SOCKET_NULL)
  5059.         {
  5060.                 CFStreamCreatePairWithSocket(NULL, (CFSocketNativeHandle)socket4FD, &readStream4, &writeStream4);
  5061.                 if (!readStream4 || !writeStream4)
  5062.                 {
  5063.                         err = [self otherError:@"Error in CFStreamCreatePairWithSocket() [IPv4]"];
  5064.                         goto Failed;
  5065.                 }
  5066.         }
  5067.        
  5068.         if (socket6FD != SOCKET_NULL)
  5069.         {
  5070.                 CFStreamCreatePairWithSocket(NULL, (CFSocketNativeHandle)socket6FD, &readStream6, &writeStream6);
  5071.                 if (!readStream6 || !writeStream6)
  5072.                 {
  5073.                         err = [self otherError:@"Error in CFStreamCreatePairWithSocket() [IPv6]"];
  5074.                         goto Failed;
  5075.                 }
  5076.         }
  5077.        
  5078.         // Ensure the CFStream's don't close our underlying socket
  5079.        
  5080.         CFReadStreamSetProperty(readStream4, kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanFalse);
  5081.         CFWriteStreamSetProperty(writeStream4, kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanFalse);
  5082.        
  5083.         CFReadStreamSetProperty(readStream6, kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanFalse);
  5084.         CFWriteStreamSetProperty(writeStream6, kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanFalse);
  5085.        
  5086.         return YES;
  5087.        
  5088. Failed:
  5089.         if (readStream4)
  5090.         {
  5091.                 CFReadStreamClose(readStream4);
  5092.                 CFRelease(readStream4);
  5093.                 readStream4 = NULL;
  5094.         }
  5095.         if (writeStream4)
  5096.         {
  5097.                 CFWriteStreamClose(writeStream4);
  5098.                 CFRelease(writeStream4);
  5099.                 writeStream4 = NULL;
  5100.         }
  5101.         if (readStream6)
  5102.         {
  5103.                 CFReadStreamClose(readStream6);
  5104.                 CFRelease(readStream6);
  5105.                 readStream6 = NULL;
  5106.         }
  5107.         if (writeStream6)
  5108.         {
  5109.                 CFWriteStreamClose(writeStream6);
  5110.                 CFRelease(writeStream6);
  5111.                 writeStream6 = NULL;
  5112.         }
  5113.        
  5114.         if (errPtr)
  5115.                 *errPtr = err;
  5116.        
  5117.         return NO;
  5118. }
  5119.  
  5120. - (BOOL)registerForStreamCallbacks:(NSError **)errPtr
  5121. {
  5122.         LogTrace();
  5123.        
  5124.         NSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @"Must be dispatched on socketQueue");
  5125.         NSAssert(readStream4 || writeStream4 || readStream6 || writeStream6, @"Read/Write streams are null");
  5126.        
  5127.         NSError *err = nil;
  5128.        
  5129.         streamContext.version = 0;
  5130.         streamContext.info = (__bridge void *)self;
  5131.         streamContext.retain = nil;
  5132.         streamContext.release = nil;
  5133.         streamContext.copyDescription = nil;
  5134.        
  5135.         CFOptionFlags readStreamEvents = kCFStreamEventErrorOccurred | kCFStreamEventEndEncountered;
  5136.         CFOptionFlags writeStreamEvents = kCFStreamEventErrorOccurred | kCFStreamEventEndEncountered;
  5137.        
  5138. //      readStreamEvents  |= (kCFStreamEventOpenCompleted | kCFStreamEventHasBytesAvailable);
  5139. //      writeStreamEvents |= (kCFStreamEventOpenCompleted | kCFStreamEventCanAcceptBytes);
  5140.        
  5141.         if (socket4FD != SOCKET_NULL)
  5142.         {
  5143.                 if (readStream4 == NULL || writeStream4 == NULL)
  5144.                 {
  5145.                         err = [self otherError:@"Read/Write stream4 is null"];
  5146.                         goto Failed;
  5147.                 }
  5148.                
  5149.                 BOOL r1 = CFReadStreamSetClient(readStream4, readStreamEvents, &CFReadStreamCallback, &streamContext);
  5150.                 BOOL r2 = CFWriteStreamSetClient(writeStream4, writeStreamEvents, &CFWriteStreamCallback, &streamContext);
  5151.                
  5152.                 if (!r1 || !r2)
  5153.                 {
  5154.                         err = [self otherError:@"Error in CFStreamSetClient(), [IPv4]"];
  5155.                         goto Failed;
  5156.                 }
  5157.         }
  5158.        
  5159.         if (socket6FD != SOCKET_NULL)
  5160.         {
  5161.                 if (readStream6 == NULL || writeStream6 == NULL)
  5162.                 {
  5163.                         err = [self otherError:@"Read/Write stream6 is null"];
  5164.                         goto Failed;
  5165.                 }
  5166.                
  5167.                 BOOL r1 = CFReadStreamSetClient(readStream6, readStreamEvents, &CFReadStreamCallback, &streamContext);
  5168.                 BOOL r2 = CFWriteStreamSetClient(writeStream6, writeStreamEvents, &CFWriteStreamCallback, &streamContext);
  5169.                
  5170.                 if (!r1 || !r2)
  5171.                 {
  5172.                         err = [self otherError:@"Error in CFStreamSetClient() [IPv6]"];
  5173.                         goto Failed;
  5174.                 }
  5175.         }
  5176.        
  5177.         return YES;
  5178.        
  5179. Failed:
  5180.         if (readStream4) {
  5181.                 CFReadStreamSetClient(readStream4, kCFStreamEventNone, NULL, NULL);
  5182.         }
  5183.         if (writeStream4) {
  5184.                 CFWriteStreamSetClient(writeStream4, kCFStreamEventNone, NULL, NULL);
  5185.         }
  5186.         if (readStream6) {
  5187.                 CFReadStreamSetClient(readStream6, kCFStreamEventNone, NULL, NULL);
  5188.         }
  5189.         if (writeStream6) {
  5190.                 CFWriteStreamSetClient(writeStream6, kCFStreamEventNone, NULL, NULL);
  5191.         }
  5192.        
  5193.         if (errPtr) *errPtr = err;
  5194.         return NO;
  5195. }
  5196.  
  5197. - (BOOL)addStreamsToRunLoop:(NSError **)errPtr
  5198. {
  5199.         LogTrace();
  5200.        
  5201.         NSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @"Must be dispatched on socketQueue");
  5202.         NSAssert(readStream4 || writeStream4 || readStream6 || writeStream6, @"Read/Write streams are null");
  5203.        
  5204.         if (!(flags & kAddedStreamListener))
  5205.         {
  5206.                 [[self class] startListenerThreadIfNeeded];
  5207.                 [[self class] performSelector:@selector(addStreamListener:)
  5208.                                      onThread:listenerThread
  5209.                                    withObject:self
  5210.                                 waitUntilDone:YES];
  5211.                
  5212.                 flags |= kAddedStreamListener;
  5213.         }
  5214.        
  5215.         return YES;
  5216. }
  5217.  
  5218. - (BOOL)openStreams:(NSError **)errPtr
  5219. {
  5220.         LogTrace();
  5221.        
  5222.         NSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @"Must be dispatched on socketQueue");
  5223.         NSAssert(readStream4 || writeStream4 || readStream6 || writeStream6, @"Read/Write streams are null");
  5224.        
  5225.         NSError *err = nil;
  5226.        
  5227.         if (socket4FD != SOCKET_NULL)
  5228.         {
  5229.                 BOOL r1 = CFReadStreamOpen(readStream4);
  5230.                 BOOL r2 = CFWriteStreamOpen(writeStream4);
  5231.                
  5232.                 if (!r1 || !r2)
  5233.                 {
  5234.                         err = [self otherError:@"Error in CFStreamOpen() [IPv4]"];
  5235.                         goto Failed;
  5236.                 }
  5237.         }
  5238.        
  5239.         if (socket6FD != SOCKET_NULL)
  5240.         {
  5241.                 BOOL r1 = CFReadStreamOpen(readStream6);
  5242.                 BOOL r2 = CFWriteStreamOpen(writeStream6);
  5243.                
  5244.                 if (!r1 || !r2)
  5245.                 {
  5246.                         err = [self otherError:@"Error in CFStreamOpen() [IPv6]"];
  5247.                         goto Failed;
  5248.                 }
  5249.         }
  5250.        
  5251.         return YES;
  5252.        
  5253. Failed:
  5254.         if (errPtr) *errPtr = err;
  5255.         return NO;
  5256. }
  5257.  
  5258. - (void)removeStreamsFromRunLoop
  5259. {
  5260.         LogTrace();
  5261.         NSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @"Must be dispatched on socketQueue");
  5262.        
  5263.         if (flags & kAddedStreamListener)
  5264.         {
  5265.                 [[self class] performSelector:@selector(removeStreamListener:)
  5266.                                      onThread:listenerThread
  5267.                                    withObject:self
  5268.                                 waitUntilDone:YES];
  5269.                
  5270.                 flags &= ~kAddedStreamListener;
  5271.         }
  5272. }
  5273.  
  5274. - (void)closeReadAndWriteStreams
  5275. {
  5276.         LogTrace();
  5277.        
  5278.         if (readStream4)
  5279.         {
  5280.                 CFReadStreamSetClient(readStream4, kCFStreamEventNone, NULL, NULL);
  5281.                 CFReadStreamClose(readStream4);
  5282.                 CFRelease(readStream4);
  5283.                 readStream4 = NULL;
  5284.         }
  5285.         if (writeStream4)
  5286.         {
  5287.                 CFWriteStreamSetClient(writeStream4, kCFStreamEventNone, NULL, NULL);
  5288.                 CFWriteStreamClose(writeStream4);
  5289.                 CFRelease(writeStream4);
  5290.                 writeStream4 = NULL;
  5291.         }
  5292.         if (readStream6)
  5293.         {
  5294.                 CFReadStreamSetClient(readStream6, kCFStreamEventNone, NULL, NULL);
  5295.                 CFReadStreamClose(readStream6);
  5296.                 CFRelease(readStream6);
  5297.                 readStream6 = NULL;
  5298.         }
  5299.         if (writeStream6)
  5300.         {
  5301.                 CFWriteStreamSetClient(writeStream6, kCFStreamEventNone, NULL, NULL);
  5302.                 CFWriteStreamClose(writeStream6);
  5303.                 CFRelease(writeStream6);
  5304.                 writeStream6 = NULL;
  5305.         }
  5306. }
  5307.  
  5308. #endif
  5309.  
  5310. #if TARGET_OS_IPHONE
  5311. - (void)applicationWillEnterForeground:(NSNotification *)notification
  5312. {
  5313.         LogTrace();
  5314.        
  5315.         // If the application was backgrounded, then iOS may have shut down our sockets.
  5316.         // So we take a quick look to see if any of them received an EOF.
  5317.        
  5318.         dispatch_block_t block = ^{ @autoreleasepool {
  5319.                
  5320.                 [self resumeReceive4Source];
  5321.                 [self resumeReceive6Source];
  5322.         }};
  5323.        
  5324.         if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
  5325.                 block();
  5326.         else
  5327.                 dispatch_async(socketQueue, block);
  5328. }
  5329. #endif
  5330.  
  5331. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  5332. #pragma mark Advanced
  5333. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  5334.  
  5335. /**
  5336.  * See header file for big discussion of this method.
  5337.  **/
  5338. - (void)markSocketQueueTargetQueue:(dispatch_queue_t)socketNewTargetQueue
  5339. {
  5340.         void *nonNullUnusedPointer = (__bridge void *)self;
  5341.         dispatch_queue_set_specific(socketNewTargetQueue, IsOnSocketQueueOrTargetQueueKey, nonNullUnusedPointer, NULL);
  5342. }
  5343.  
  5344. /**
  5345.  * See header file for big discussion of this method.
  5346.  **/
  5347. - (void)unmarkSocketQueueTargetQueue:(dispatch_queue_t)socketOldTargetQueue
  5348. {
  5349.         dispatch_queue_set_specific(socketOldTargetQueue, IsOnSocketQueueOrTargetQueueKey, NULL, NULL);
  5350. }
  5351.  
  5352. - (void)performBlock:(dispatch_block_t)block
  5353. {
  5354.         if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
  5355.                 block();
  5356.         else
  5357.                 dispatch_sync(socketQueue, block);
  5358. }
  5359.  
  5360. - (int)socketFD
  5361. {
  5362.         if (! dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
  5363.         {
  5364.                 LogWarn(@"%@: %@ - Method only available from within the context of a performBlock: invocation",
  5365.                                 THIS_FILE, THIS_METHOD);
  5366.                 return SOCKET_NULL;
  5367.         }
  5368.        
  5369.         if (socket4FD != SOCKET_NULL)
  5370.                 return socket4FD;
  5371.         else
  5372.                 return socket6FD;
  5373. }
  5374.  
  5375. - (int)socket4FD
  5376. {
  5377.         if (! dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
  5378.         {
  5379.                 LogWarn(@"%@: %@ - Method only available from within the context of a performBlock: invocation",
  5380.                                 THIS_FILE, THIS_METHOD);
  5381.                 return SOCKET_NULL;
  5382.         }
  5383.        
  5384.         return socket4FD;
  5385. }
  5386.  
  5387. - (int)socket6FD
  5388. {
  5389.         if (! dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
  5390.         {
  5391.                 LogWarn(@"%@: %@ - Method only available from within the context of a performBlock: invocation",
  5392.                                 THIS_FILE, THIS_METHOD);
  5393.                 return SOCKET_NULL;
  5394.         }
  5395.        
  5396.         return socket6FD;
  5397. }
  5398.  
  5399. #if TARGET_OS_IPHONE
  5400.  
  5401. - (CFReadStreamRef)readStream
  5402. {
  5403.         if (! dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
  5404.         {
  5405.                 LogWarn(@"%@: %@ - Method only available from within the context of a performBlock: invocation",
  5406.                                 THIS_FILE, THIS_METHOD);
  5407.                 return NULL;
  5408.         }
  5409.        
  5410.         NSError *err = nil;
  5411.         if (![self createReadAndWriteStreams:&err])
  5412.         {
  5413.                 LogError(@"Error creating CFStream(s): %@", err);
  5414.                 return NULL;
  5415.         }
  5416.        
  5417.         // Todo...
  5418.        
  5419.         if (readStream4)
  5420.                 return readStream4;
  5421.         else
  5422.                 return readStream6;
  5423. }
  5424.  
  5425. - (CFWriteStreamRef)writeStream
  5426. {
  5427.         if (! dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
  5428.         {
  5429.                 LogWarn(@"%@: %@ - Method only available from within the context of a performBlock: invocation",
  5430.                                 THIS_FILE, THIS_METHOD);
  5431.                 return NULL;
  5432.         }
  5433.        
  5434.         NSError *err = nil;
  5435.         if (![self createReadAndWriteStreams:&err])
  5436.         {
  5437.                 LogError(@"Error creating CFStream(s): %@", err);
  5438.                 return NULL;
  5439.         }
  5440.        
  5441.         if (writeStream4)
  5442.                 return writeStream4;
  5443.         else
  5444.                 return writeStream6;
  5445. }
  5446.  
  5447. - (BOOL)enableBackgroundingOnSockets
  5448. {
  5449.         if (! dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
  5450.         {
  5451.                 LogWarn(@"%@: %@ - Method only available from within the context of a performBlock: invocation",
  5452.                                 THIS_FILE, THIS_METHOD);
  5453.                 return NO;
  5454.         }
  5455.        
  5456.         // Why is this commented out?
  5457.         // See comments below.
  5458.        
  5459. //      NSError *err = nil;
  5460. //      if (![self createReadAndWriteStreams:&err])
  5461. //      {
  5462. //              LogError(@"Error creating CFStream(s): %@", err);
  5463. //              return NO;
  5464. //      }
  5465. //     
  5466. //      LogVerbose(@"Enabling backgrouding on socket");
  5467. //     
  5468. //      BOOL r1, r2;
  5469. //     
  5470. //      if (readStream4 && writeStream4)
  5471. //      {
  5472. //              r1 = CFReadStreamSetProperty(readStream4, kCFStreamNetworkServiceType, kCFStreamNetworkServiceTypeVoIP);
  5473. //              r2 = CFWriteStreamSetProperty(writeStream4, kCFStreamNetworkServiceType, kCFStreamNetworkServiceTypeVoIP);
  5474. //             
  5475. //              if (!r1 || !r2)
  5476. //              {
  5477. //                      LogError(@"Error setting voip type (IPv4)");
  5478. //                      return NO;
  5479. //              }
  5480. //      }
  5481. //     
  5482. //      if (readStream6 && writeStream6)
  5483. //      {
  5484. //              r1 = CFReadStreamSetProperty(readStream6, kCFStreamNetworkServiceType, kCFStreamNetworkServiceTypeVoIP);
  5485. //              r2 = CFWriteStreamSetProperty(writeStream6, kCFStreamNetworkServiceType, kCFStreamNetworkServiceTypeVoIP);
  5486. //             
  5487. //              if (!r1 || !r2)
  5488. //              {
  5489. //                      LogError(@"Error setting voip type (IPv6)");
  5490. //                      return NO;
  5491. //              }
  5492. //      }
  5493. //     
  5494. //      return YES;
  5495.        
  5496.         // The above code will actually appear to work.
  5497.         // The methods will return YES, and everything will appear fine.
  5498.         //
  5499.         // One tiny problem: the sockets will still get closed when the app gets backgrounded.
  5500.         //
  5501.         // Apple does not officially support backgrounding UDP sockets.
  5502.        
  5503.         return NO;
  5504. }
  5505.  
  5506. #endif
  5507.  
  5508. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  5509. #pragma mark Class Methods
  5510. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  5511.  
  5512. + (NSString *)hostFromSockaddr4:(const struct sockaddr_in *)pSockaddr4
  5513. {
  5514.         char addrBuf[INET_ADDRSTRLEN];
  5515.        
  5516.         if (inet_ntop(AF_INET, &pSockaddr4->sin_addr, addrBuf, (socklen_t)sizeof(addrBuf)) == NULL)
  5517.         {
  5518.                 addrBuf[0] = '\0';
  5519.         }
  5520.        
  5521.         return [NSString stringWithCString:addrBuf encoding:NSASCIIStringEncoding];
  5522. }
  5523.  
  5524. + (NSString *)hostFromSockaddr6:(const struct sockaddr_in6 *)pSockaddr6
  5525. {
  5526.         char addrBuf[INET6_ADDRSTRLEN];
  5527.        
  5528.         if (inet_ntop(AF_INET6, &pSockaddr6->sin6_addr, addrBuf, (socklen_t)sizeof(addrBuf)) == NULL)
  5529.         {
  5530.                 addrBuf[0] = '\0';
  5531.         }
  5532.        
  5533.         return [NSString stringWithCString:addrBuf encoding:NSASCIIStringEncoding];
  5534. }
  5535.  
  5536. + (uint16_t)portFromSockaddr4:(const struct sockaddr_in *)pSockaddr4
  5537. {
  5538.         return ntohs(pSockaddr4->sin_port);
  5539. }
  5540.  
  5541. + (uint16_t)portFromSockaddr6:(const struct sockaddr_in6 *)pSockaddr6
  5542. {
  5543.         return ntohs(pSockaddr6->sin6_port);
  5544. }
  5545.  
  5546. + (NSString *)hostFromAddress:(NSData *)address
  5547. {
  5548.         NSString *host = nil;
  5549.         [self getHost:&host port:NULL family:NULL fromAddress:address];
  5550.        
  5551.         return host;
  5552. }
  5553.  
  5554. + (uint16_t)portFromAddress:(NSData *)address
  5555. {
  5556.         uint16_t port = 0;
  5557.         [self getHost:NULL port:&port family:NULL fromAddress:address];
  5558.        
  5559.         return port;
  5560. }
  5561.  
  5562. + (int)familyFromAddress:(NSData *)address
  5563. {
  5564.         int af = AF_UNSPEC;
  5565.         [self getHost:NULL port:NULL family:&af fromAddress:address];
  5566.        
  5567.         return af;
  5568. }
  5569.  
  5570. + (BOOL)isIPv4Address:(NSData *)address
  5571. {
  5572.         int af = AF_UNSPEC;
  5573.         [self getHost:NULL port:NULL family:&af fromAddress:address];
  5574.        
  5575.         return (af == AF_INET);
  5576. }
  5577.  
  5578. + (BOOL)isIPv6Address:(NSData *)address
  5579. {
  5580.         int af = AF_UNSPEC;
  5581.         [self getHost:NULL port:NULL family:&af fromAddress:address];
  5582.        
  5583.         return (af == AF_INET6);
  5584. }
  5585.  
  5586. + (BOOL)getHost:(NSString **)hostPtr port:(uint16_t *)portPtr fromAddress:(NSData *)address
  5587. {
  5588.         return [self getHost:hostPtr port:portPtr family:NULL fromAddress:address];
  5589. }
  5590.  
  5591. + (BOOL)getHost:(NSString **)hostPtr port:(uint16_t *)portPtr family:(int *)afPtr fromAddress:(NSData *)address
  5592. {
  5593.         if ([address length] >= sizeof(struct sockaddr))
  5594.         {
  5595.                 const struct sockaddr *addrX = (const struct sockaddr *)[address bytes];
  5596.                
  5597.                 if (addrX->sa_family == AF_INET)
  5598.                 {
  5599.                         if ([address length] >= sizeof(struct sockaddr_in))
  5600.                         {
  5601.                                 const struct sockaddr_in *addr4 = (const struct sockaddr_in *)(const void *)addrX;
  5602.                                
  5603.                                 if (hostPtr) *hostPtr = [self hostFromSockaddr4:addr4];
  5604.                                 if (portPtr) *portPtr = [self portFromSockaddr4:addr4];
  5605.                                 if (afPtr)   *afPtr   = AF_INET;
  5606.                                
  5607.                                 return YES;
  5608.                         }
  5609.                 }
  5610.                 else if (addrX->sa_family == AF_INET6)
  5611.                 {
  5612.                         if ([address length] >= sizeof(struct sockaddr_in6))
  5613.                         {
  5614.                                 const struct sockaddr_in6 *addr6 = (const struct sockaddr_in6 *)(const void *)addrX;
  5615.                                
  5616.                                 if (hostPtr) *hostPtr = [self hostFromSockaddr6:addr6];
  5617.                                 if (portPtr) *portPtr = [self portFromSockaddr6:addr6];
  5618.                                 if (afPtr)   *afPtr   = AF_INET6;
  5619.                                
  5620.                                 return YES;
  5621.                         }
  5622.                 }
  5623.         }
  5624.        
  5625.         if (hostPtr) *hostPtr = nil;
  5626.         if (portPtr) *portPtr = 0;
  5627.         if (afPtr)   *afPtr   = AF_UNSPEC;
  5628.        
  5629.         return NO;
  5630. }
  5631.  
  5632. @end
  5633.