OSDN Git Service

Bug fix for issue introduced in r105.
[syncr/master.git] / CocoaAsyncSocket / CocoaAsyncSocket-5.6.1 / AsyncUdpSocket.m
diff --git a/CocoaAsyncSocket/CocoaAsyncSocket-5.6.1/AsyncUdpSocket.m b/CocoaAsyncSocket/CocoaAsyncSocket-5.6.1/AsyncUdpSocket.m
deleted file mode 100644 (file)
index 8f903b7..0000000
+++ /dev/null
@@ -1,2343 +0,0 @@
-//
-//  AsyncUdpSocket.m
-//  
-//  This class is in the public domain.
-//  Originally created by Robbie Hanson on Wed Oct 01 2008.
-//  Updated and maintained by Deusty Designs and the Mac development community.
-//
-//  http://code.google.com/p/cocoaasyncsocket/
-//
-
-#import "AsyncUdpSocket.h"
-#import <sys/socket.h>
-#import <netinet/in.h>
-#import <arpa/inet.h>
-#import <sys/ioctl.h>
-#import <net/if.h>
-#import <netdb.h>
-
-#if TARGET_OS_IPHONE
-// Note: You may need to add the CFNetwork Framework to your project
-#import <CFNetwork/CFNetwork.h>
-#endif
-
-
-#define SENDQUEUE_CAPACITY       5   // Initial capacity
-#define RECEIVEQUEUE_CAPACITY 5   // Initial capacity
-
-#define DEFAULT_MAX_RECEIVE_BUFFER_SIZE 9216
-
-NSString *const AsyncUdpSocketException = @"AsyncUdpSocketException";
-NSString *const AsyncUdpSocketErrorDomain = @"AsyncUdpSocketErrorDomain";
-
-#if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5
-// Mutex lock used by all instances of AsyncUdpSocket, to protect getaddrinfo.
-// Prior to Mac OS X 10.5 this method was not thread-safe.
-static NSString *getaddrinfoLock = @"lock";
-#endif
-
-enum AsyncUdpSocketFlags
-{
-       kDidBind                 = 1 <<  0,  // If set, bind has been called.
-       kDidConnect              = 1 <<  1,  // If set, connect has been called.
-       kSock4CanAcceptBytes     = 1 <<  2,  // If set, we know socket4 can accept bytes. If unset, it's unknown.
-       kSock6CanAcceptBytes     = 1 <<  3,  // If set, we know socket6 can accept bytes. If unset, it's unknown.
-       kSock4HasBytesAvailable  = 1 <<  4,  // If set, we know socket4 has bytes available. If unset, it's unknown.
-       kSock6HasBytesAvailable  = 1 <<  5,  // If set, we know socket6 has bytes available. If unset, it's unknown.
-       kForbidSendReceive       = 1 <<  6,  // If set, no new send or receive operations are allowed to be queued.
-       kCloseAfterSends         = 1 <<  7,  // If set, close as soon as no more sends are queued.
-       kCloseAfterReceives      = 1 <<  8,  // If set, close as soon as no more receives are queued.
-       kDidClose                = 1 <<  9,  // If set, the socket has been closed, and should not be used anymore.
-       kDequeueSendScheduled    = 1 << 10,  // If set, a maybeDequeueSend operation is already scheduled.
-       kDequeueReceiveScheduled = 1 << 11,  // If set, a maybeDequeueReceive operation is already scheduled.
-       kFlipFlop                = 1 << 12,  // Used to alternate between IPv4 and IPv6 sockets.
-};
-
-@interface AsyncUdpSocket (Private)
-
-// Run Loop
-- (void)runLoopAddSource:(CFRunLoopSourceRef)source;
-- (void)runLoopRemoveSource:(CFRunLoopSourceRef)source;
-- (void)runLoopAddTimer:(NSTimer *)timer;
-- (void)runLoopRemoveTimer:(NSTimer *)timer;
-
-// Utilities
-- (NSString *)addressHost4:(struct sockaddr_in *)pSockaddr4;
-- (NSString *)addressHost6:(struct sockaddr_in6 *)pSockaddr6;
-- (NSString *)addressHost:(struct sockaddr *)pSockaddr;
-
-// Disconnect Implementation
-- (void)emptyQueues;
-- (void)closeSocket4;
-- (void)closeSocket6;
-- (void)maybeScheduleClose;
-
-// Errors
-- (NSError *)getErrnoError;
-- (NSError *)getSocketError;
-- (NSError *)getIPv4UnavailableError;
-- (NSError *)getIPv6UnavailableError;
-- (NSError *)getSendTimeoutError;
-- (NSError *)getReceiveTimeoutError;
-
-// Diagnostics
-- (NSString *)connectedHost:(CFSocketRef)socket;
-- (UInt16)connectedPort:(CFSocketRef)socket;
-- (NSString *)localHost:(CFSocketRef)socket;
-- (UInt16)localPort:(CFSocketRef)socket;
-
-// Sending
-- (BOOL)canAcceptBytes:(CFSocketRef)sockRef;
-- (void)scheduleDequeueSend;
-- (void)maybeDequeueSend;
-- (void)doSend:(CFSocketRef)sockRef;
-- (void)completeCurrentSend;
-- (void)failCurrentSend:(NSError *)error;
-- (void)endCurrentSend;
-- (void)doSendTimeout:(NSTimer *)timer;
-
-// Receiving
-- (BOOL)hasBytesAvailable:(CFSocketRef)sockRef;
-- (void)scheduleDequeueReceive;
-- (void)maybeDequeueReceive;
-- (void)doReceive4;
-- (void)doReceive6;
-- (void)doReceive:(CFSocketRef)sockRef;
-- (BOOL)maybeCompleteCurrentReceive;
-- (void)failCurrentReceive:(NSError *)error;
-- (void)endCurrentReceive;
-- (void)doReceiveTimeout:(NSTimer *)timer;
-
-@end
-
-static void MyCFSocketCallback(CFSocketRef, CFSocketCallBackType, CFDataRef, const void *, void *);
-
-////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-#pragma mark -
-////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-
-/**
- * The AsyncSendPacket encompasses the instructions for a single send/write.
-**/
-@interface AsyncSendPacket : NSObject
-{
-@public
-       NSData *buffer;
-       NSData *address;
-       NSTimeInterval timeout;
-       long tag;
-}
-- (id)initWithData:(NSData *)d address:(NSData *)a timeout:(NSTimeInterval)t tag:(long)i;
-@end
-
-@implementation AsyncSendPacket
-
-- (id)initWithData:(NSData *)d address:(NSData *)a timeout:(NSTimeInterval)t tag:(long)i
-{
-       if((self = [super init]))
-       {
-               buffer = [d retain];
-               address = [a retain];
-               timeout = t;
-               tag = i;
-       }
-       return self;
-}
-
-- (void)dealloc
-{
-       [buffer release];
-       [address release];
-       [super dealloc];
-}
-
-@end
-
-////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-#pragma mark -
-////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-
-/**
- * The AsyncReceivePacket encompasses the instructions for a single receive/read.
-**/
-@interface AsyncReceivePacket : NSObject
-{
-@public
-       NSTimeInterval timeout;
-       long tag;
-       NSMutableData *buffer;
-       NSString *host;
-       UInt16 port;
-}
-- (id)initWithTimeout:(NSTimeInterval)t tag:(long)i;
-@end
-
-@implementation AsyncReceivePacket
-
-- (id)initWithTimeout:(NSTimeInterval)t tag:(long)i
-{
-       if((self = [super init]))
-       {
-               timeout = t;
-               tag = i;
-               
-               buffer = nil;
-               host = nil;
-               port = 0;
-       }
-       return self;
-}
-
-- (void)dealloc
-{
-       [buffer release];
-       [host release];
-       [super dealloc];
-}
-
-@end
-
-////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-#pragma mark -
-////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-
-@implementation AsyncUdpSocket
-
-- (id)initWithDelegate:(id)delegate userData:(long)userData enableIPv4:(BOOL)enableIPv4 enableIPv6:(BOOL)enableIPv6
-{
-       if((self = [super init]))
-       {
-               theFlags = 0;
-               theDelegate = delegate;
-               theUserData = userData;
-               maxReceiveBufferSize = DEFAULT_MAX_RECEIVE_BUFFER_SIZE;
-               
-               theSendQueue = [[NSMutableArray alloc] initWithCapacity:SENDQUEUE_CAPACITY];
-               theCurrentSend = nil;
-               theSendTimer = nil;
-               
-               theReceiveQueue = [[NSMutableArray alloc] initWithCapacity:RECEIVEQUEUE_CAPACITY];
-               theCurrentReceive = nil;
-               theReceiveTimer = nil;
-               
-               // Socket context
-               theContext.version = 0;
-               theContext.info = self;
-               theContext.retain = nil;
-               theContext.release = nil;
-               theContext.copyDescription = nil;
-               
-               // Create the sockets
-               theSocket4 = NULL;
-               theSocket6 = NULL;
-               
-               if(enableIPv4)
-               {
-                       theSocket4 = CFSocketCreate(kCFAllocatorDefault,
-                                                                               PF_INET,
-                                                                               SOCK_DGRAM,
-                                                                               IPPROTO_UDP,
-                                                                               kCFSocketReadCallBack | kCFSocketWriteCallBack,
-                                                                               (CFSocketCallBack)&MyCFSocketCallback,
-                                                                               &theContext);
-               }
-               if(enableIPv6)
-               {
-                       theSocket6 = CFSocketCreate(kCFAllocatorDefault,
-                                                                               PF_INET6,
-                                                                               SOCK_DGRAM,
-                                                                               IPPROTO_UDP,
-                                                                               kCFSocketReadCallBack | kCFSocketWriteCallBack,
-                                                                               (CFSocketCallBack)&MyCFSocketCallback,
-                                                                               &theContext);
-               }
-               
-               // Disable continuous callbacks for read and write.
-               // If we don't do this, the socket(s) will just sit there firing read callbacks
-               // at us hundreds of times a second if we don't immediately read the available data.
-               if(theSocket4)
-               {
-                       CFSocketSetSocketFlags(theSocket4, kCFSocketCloseOnInvalidate);
-               }
-               if(theSocket6)
-               {
-                       CFSocketSetSocketFlags(theSocket6, kCFSocketCloseOnInvalidate);
-               }
-               
-               // Get the CFRunLoop to which the socket should be attached.
-               theRunLoop = CFRunLoopGetCurrent();
-               
-               // Set default run loop modes
-               theRunLoopModes = [[NSArray arrayWithObject:NSDefaultRunLoopMode] retain];
-               
-               // Attach the sockets to the run loop
-               
-               if(theSocket4)
-               {
-                       theSource4 = CFSocketCreateRunLoopSource(kCFAllocatorDefault, theSocket4, 0);
-                       [self runLoopAddSource:theSource4];
-               }
-               
-               if(theSocket6)
-               {
-                       theSource6 = CFSocketCreateRunLoopSource(kCFAllocatorDefault, theSocket6, 0);
-                       [self runLoopAddSource:theSource6];
-               }
-               
-               cachedLocalPort = 0;
-               cachedConnectedPort = 0;
-       }
-       return self;
-}
-
-- (id)init
-{
-       return [self initWithDelegate:nil userData:0 enableIPv4:YES enableIPv6:YES];
-}
-
-- (id)initWithDelegate:(id)delegate
-{
-       return [self initWithDelegate:delegate userData:0 enableIPv4:YES enableIPv6:YES];
-}
-
-- (id)initWithDelegate:(id)delegate userData:(long)userData
-{
-       return [self initWithDelegate:delegate userData:userData enableIPv4:YES enableIPv6:YES];
-}
-
-- (id)initIPv4
-{
-       return [self initWithDelegate:nil userData:0 enableIPv4:YES enableIPv6:NO];
-}
-
-- (id)initIPv6
-{
-       return [self initWithDelegate:nil userData:0 enableIPv4:NO enableIPv6:YES];
-}
-
-- (void) dealloc
-{
-       [self close];
-       [theSendQueue release];
-       [theReceiveQueue release];
-       [theRunLoopModes release];
-       [cachedLocalHost release];
-       [cachedConnectedHost release];
-       [NSObject cancelPreviousPerformRequestsWithTarget:theDelegate selector:@selector(onUdpSocketDidClose:) object:self];
-       [NSObject cancelPreviousPerformRequestsWithTarget:self];
-       [super dealloc];
-}
-
-////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-#pragma mark Accessors
-////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-
-- (id)delegate
-{
-       return theDelegate;
-}
-
-- (void)setDelegate:(id)delegate
-{
-       theDelegate = delegate;
-}
-
-- (long)userData
-{
-       return theUserData;
-}
-
-- (void)setUserData:(long)userData
-{
-       theUserData = userData;
-}
-
-////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-#pragma mark Run Loop
-////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-
-- (void)runLoopAddSource:(CFRunLoopSourceRef)source
-{
-       unsigned i, count = [theRunLoopModes count];
-       for(i = 0; i < count; i++)
-       {
-               CFStringRef runLoopMode = (CFStringRef)[theRunLoopModes objectAtIndex:i];
-               CFRunLoopAddSource(theRunLoop, source, runLoopMode);
-       }
-}
-
-- (void)runLoopRemoveSource:(CFRunLoopSourceRef)source
-{
-       unsigned i, count = [theRunLoopModes count];
-       for(i = 0; i < count; i++)
-       {
-               CFStringRef runLoopMode = (CFStringRef)[theRunLoopModes objectAtIndex:i];
-               CFRunLoopRemoveSource(theRunLoop, source, runLoopMode);
-       }
-}
-
-- (void)runLoopAddTimer:(NSTimer *)timer
-{
-       unsigned i, count = [theRunLoopModes count];
-       for(i = 0; i < count; i++)
-       {
-               CFStringRef runLoopMode = (CFStringRef)[theRunLoopModes objectAtIndex:i];
-               CFRunLoopAddTimer(theRunLoop, (CFRunLoopTimerRef)timer, runLoopMode);
-       }
-}
-
-- (void)runLoopRemoveTimer:(NSTimer *)timer
-{
-       unsigned i, count = [theRunLoopModes count];
-       for(i = 0; i < count; i++)              
-       {
-               CFStringRef runLoopMode = (CFStringRef)[theRunLoopModes objectAtIndex:i];
-               CFRunLoopRemoveTimer(theRunLoop, (CFRunLoopTimerRef)timer, runLoopMode);
-       }
-}
-
-////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-#pragma mark Configuration
-////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-
-- (UInt32)maxReceiveBufferSize
-{
-       return maxReceiveBufferSize;
-}
-
-- (void)setMaxReceiveBufferSize:(UInt32)max
-{
-       maxReceiveBufferSize = max;
-}
-
-/**
- * See the header file for a full explanation of this method.
-**/
-- (BOOL)moveToRunLoop:(NSRunLoop *)runLoop
-{
-       NSAssert((theRunLoop == NULL) || (theRunLoop == CFRunLoopGetCurrent()),
-                        @"moveToRunLoop must be called from within the current RunLoop!");
-       
-       if(runLoop == nil)
-       {
-               return NO;
-       }
-       if(theRunLoop == [runLoop getCFRunLoop])
-       {
-               return YES;
-       }
-       
-       [NSObject cancelPreviousPerformRequestsWithTarget:self];
-       theFlags &= ~kDequeueSendScheduled;
-       theFlags &= ~kDequeueReceiveScheduled;
-       
-       if(theSource4) [self runLoopRemoveSource:theSource4];
-       if(theSource6) [self runLoopRemoveSource:theSource6];
-       
-       // We do not retain the timers - they get retained by the runloop when we add them as a source.
-       // Since we're about to remove them as a source, we retain now, and release again below.
-       [theSendTimer retain];
-       [theReceiveTimer retain];
-       
-       if(theSendTimer)    [self runLoopRemoveTimer:theSendTimer];
-       if(theReceiveTimer) [self runLoopRemoveTimer:theReceiveTimer];
-       
-       theRunLoop = [runLoop getCFRunLoop];
-       
-       if(theSendTimer)    [self runLoopAddTimer:theSendTimer];
-       if(theReceiveTimer) [self runLoopAddTimer:theReceiveTimer];
-       
-       // Release timers since we retained them above
-       [theSendTimer release];
-       [theReceiveTimer release];
-       
-       if(theSource4) [self runLoopAddSource:theSource4];
-       if(theSource6) [self runLoopAddSource:theSource6];
-       
-       [runLoop performSelector:@selector(maybeDequeueSend) target:self argument:nil order:0 modes:theRunLoopModes];
-       [runLoop performSelector:@selector(maybeDequeueReceive) target:self argument:nil order:0 modes:theRunLoopModes];
-       [runLoop performSelector:@selector(maybeScheduleClose) target:self argument:nil order:0 modes:theRunLoopModes];
-       
-       return YES;
-}
-
-/**
- * See the header file for a full explanation of this method.
-**/
-- (BOOL)setRunLoopModes:(NSArray *)runLoopModes
-{
-       NSAssert((theRunLoop == NULL) || (theRunLoop == CFRunLoopGetCurrent()),
-                        @"setRunLoopModes must be called from within the current RunLoop!");
-       
-       if([runLoopModes count] == 0)
-       {
-               return NO;
-       }
-       if([theRunLoopModes isEqualToArray:runLoopModes])
-       {
-               return YES;
-       }
-       
-       [NSObject cancelPreviousPerformRequestsWithTarget:self];
-       theFlags &= ~kDequeueSendScheduled;
-       theFlags &= ~kDequeueReceiveScheduled;
-       
-       if(theSource4) [self runLoopRemoveSource:theSource4];
-       if(theSource6) [self runLoopRemoveSource:theSource6];
-       
-       // We do not retain the timers - they get retained by the runloop when we add them as a source.
-       // Since we're about to remove them as a source, we retain now, and release again below.
-       [theSendTimer retain];
-       [theReceiveTimer retain];
-       
-       if(theSendTimer)    [self runLoopRemoveTimer:theSendTimer];
-       if(theReceiveTimer) [self runLoopRemoveTimer:theReceiveTimer];
-       
-       [theRunLoopModes release];
-       theRunLoopModes = [runLoopModes copy];
-       
-       if(theSendTimer)    [self runLoopAddTimer:theSendTimer];
-       if(theReceiveTimer) [self runLoopAddTimer:theReceiveTimer];
-       
-       // Release timers since we retained them above
-       [theSendTimer release];
-       [theReceiveTimer release];
-       
-       if(theSource4) [self runLoopAddSource:theSource4];
-       if(theSource6) [self runLoopAddSource:theSource6];
-       
-       [self performSelector:@selector(maybeDequeueSend) withObject:nil afterDelay:0 inModes:theRunLoopModes];
-       [self performSelector:@selector(maybeDequeueReceive) withObject:nil afterDelay:0 inModes:theRunLoopModes];
-       [self performSelector:@selector(maybeScheduleClose) withObject:nil afterDelay:0 inModes:theRunLoopModes];
-       
-       return YES;
-}
-
-- (NSArray *)runLoopModes
-{
-       return [[theRunLoopModes retain] autorelease];
-}
-
-////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-#pragma mark Utilities:
-////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-
-/**
- * Attempts to convert the given host/port into and IPv4 and/or IPv6 data structure.
- * The data structure is of type sockaddr_in for IPv4 and sockaddr_in6 for IPv6.
- *
- * Returns zero on success, or one of the error codes listed in gai_strerror if an error occurs (as per getaddrinfo).
-**/
-- (int)convertForBindHost:(NSString *)host
-                                        port:(UInt16)port
-                        intoAddress4:(NSData **)address4
-                                address6:(NSData **)address6
-{
-       if(host == nil || ([host length] == 0))
-       {
-               // Use ANY address
-               struct sockaddr_in nativeAddr;
-               nativeAddr.sin_len         = sizeof(struct sockaddr_in);
-               nativeAddr.sin_family      = AF_INET;
-               nativeAddr.sin_port        = htons(port);
-               nativeAddr.sin_addr.s_addr = htonl(INADDR_ANY);
-               memset(&(nativeAddr.sin_zero), 0, sizeof(nativeAddr.sin_zero));
-               
-               struct sockaddr_in6 nativeAddr6;
-               nativeAddr6.sin6_len       = sizeof(struct sockaddr_in6);
-               nativeAddr6.sin6_family    = AF_INET6;
-               nativeAddr6.sin6_port      = htons(port);
-               nativeAddr6.sin6_flowinfo  = 0;
-               nativeAddr6.sin6_addr      = in6addr_any;
-               nativeAddr6.sin6_scope_id  = 0;
-               
-               // Wrap the native address structures for CFSocketSetAddress.
-               if(address4) *address4 = [NSData dataWithBytes:&nativeAddr length:sizeof(nativeAddr)];
-               if(address6) *address6 = [NSData dataWithBytes:&nativeAddr6 length:sizeof(nativeAddr6)];
-               
-               return 0;
-       }
-       else if([host isEqualToString:@"localhost"] || [host isEqualToString:@"loopback"])
-       {
-               // Note: getaddrinfo("localhost",...) fails on 10.5.3
-               
-               // Use LOOPBACK address
-               struct sockaddr_in nativeAddr;
-               nativeAddr.sin_len         = sizeof(struct sockaddr_in);
-               nativeAddr.sin_family      = AF_INET;
-               nativeAddr.sin_port        = htons(port);
-               nativeAddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
-               memset(&(nativeAddr.sin_zero), 0, sizeof(nativeAddr.sin_zero));
-               
-               struct sockaddr_in6 nativeAddr6;
-               nativeAddr6.sin6_len       = sizeof(struct sockaddr_in6);
-               nativeAddr6.sin6_family    = AF_INET6;
-               nativeAddr6.sin6_port      = htons(port);
-               nativeAddr6.sin6_flowinfo  = 0;
-               nativeAddr6.sin6_addr      = in6addr_loopback;
-               nativeAddr6.sin6_scope_id  = 0;
-               
-               // Wrap the native address structures for CFSocketSetAddress.
-               if(address4) *address4 = [NSData dataWithBytes:&nativeAddr length:sizeof(nativeAddr)];
-               if(address6) *address6 = [NSData dataWithBytes:&nativeAddr6 length:sizeof(nativeAddr6)];
-               
-               return 0;
-       }
-       else
-       {
-               NSString *portStr = [NSString stringWithFormat:@"%hu", port];
-               
-#if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5
-               @synchronized (getaddrinfoLock)
-#endif
-               {
-                       struct addrinfo hints, *res, *res0;
-                       
-                       memset(&hints, 0, sizeof(hints));
-                       hints.ai_family   = PF_UNSPEC;
-                       hints.ai_socktype = SOCK_DGRAM;
-                       hints.ai_protocol = IPPROTO_UDP;
-                       hints.ai_flags    = AI_PASSIVE;
-                       
-                       int error = getaddrinfo([host UTF8String], [portStr UTF8String], &hints, &res0);
-                       
-                       if(error) return error;
-                       
-                       for(res = res0; res; res = res->ai_next)
-                       {
-                               if(address4 && !*address4 && (res->ai_family == AF_INET))
-                               {
-                                       // Found IPv4 address
-                                       // Wrap the native address structures for CFSocketSetAddress.
-                                       if(address4) *address4 = [NSData dataWithBytes:res->ai_addr length:res->ai_addrlen];
-                               }
-                               else if(address6 && !*address6 && (res->ai_family == AF_INET6))
-                               {
-                                       // Found IPv6 address
-                                       // Wrap the native address structures for CFSocketSetAddress.
-                                       if(address6) *address6 = [NSData dataWithBytes:res->ai_addr length:res->ai_addrlen];
-                               }
-                       }
-                       freeaddrinfo(res0);
-               }
-               
-               return 0;
-       }
-}
-
-/**
- * Attempts to convert the given host/port into and IPv4 and/or IPv6 data structure.
- * The data structure is of type sockaddr_in for IPv4 and sockaddr_in6 for IPv6.
- *
- * Returns zero on success, or one of the error codes listed in gai_strerror if an error occurs (as per getaddrinfo).
-**/
-- (int)convertForSendHost:(NSString *)host
-                                         port:(UInt16)port
-                         intoAddress4:(NSData **)address4
-                                 address6:(NSData **)address6
-{
-       if(host == nil || ([host length] == 0))
-       {
-               // We're not binding, so what are we supposed to do with this?
-               return EAI_NONAME;
-       }
-       else if([host isEqualToString:@"localhost"] || [host isEqualToString:@"loopback"])
-       {
-               // Note: getaddrinfo("localhost",...) fails on 10.5.3
-               
-               // Use LOOPBACK address
-               struct sockaddr_in nativeAddr;
-               nativeAddr.sin_len         = sizeof(struct sockaddr_in);
-               nativeAddr.sin_family      = AF_INET;
-               nativeAddr.sin_port        = htons(port);
-               nativeAddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
-               memset(&(nativeAddr.sin_zero), 0, sizeof(nativeAddr.sin_zero));
-               
-               struct sockaddr_in6 nativeAddr6;
-               nativeAddr6.sin6_len       = sizeof(struct sockaddr_in6);
-               nativeAddr6.sin6_family    = AF_INET6;
-               nativeAddr6.sin6_port      = htons(port);
-               nativeAddr6.sin6_flowinfo  = 0;
-               nativeAddr6.sin6_addr      = in6addr_loopback;
-               nativeAddr6.sin6_scope_id  = 0;
-               
-               // Wrap the native address structures for CFSocketSetAddress.
-               if(address4) *address4 = [NSData dataWithBytes:&nativeAddr length:sizeof(nativeAddr)];
-               if(address6) *address6 = [NSData dataWithBytes:&nativeAddr6 length:sizeof(nativeAddr6)];
-               
-               return 0;
-       }
-       else
-       {
-               NSString *portStr = [NSString stringWithFormat:@"%hu", port];
-
-#if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5              
-               @synchronized (getaddrinfoLock)
-#endif
-               {
-                       struct addrinfo hints, *res, *res0;
-                       
-                       memset(&hints, 0, sizeof(hints));
-                       hints.ai_family   = PF_UNSPEC;
-                       hints.ai_socktype = SOCK_DGRAM;
-                       hints.ai_protocol = IPPROTO_UDP;
-                       // No passive flag on a send or connect
-                       
-                       int error = getaddrinfo([host UTF8String], [portStr UTF8String], &hints, &res0);
-                       
-                       if(error) return error;
-                       
-                       for(res = res0; res; res = res->ai_next)
-                       {
-                               if(address4 && !*address4 && (res->ai_family == AF_INET))
-                               {
-                                       // Found IPv4 address
-                                       // Wrap the native address structures for CFSocketSetAddress.
-                                       if(address4) *address4 = [NSData dataWithBytes:res->ai_addr length:res->ai_addrlen];
-                               }
-                               else if(address6 && !*address6 && (res->ai_family == AF_INET6))
-                               {
-                                       // Found IPv6 address
-                                       // Wrap the native address structures for CFSocketSetAddress.
-                                       if(address6) *address6 = [NSData dataWithBytes:res->ai_addr length:res->ai_addrlen];
-                               }
-                       }
-                       freeaddrinfo(res0);
-               }
-               
-               return 0;
-       }
-}
-
-- (NSString *)addressHost4:(struct sockaddr_in *)pSockaddr4
-{
-       char addrBuf[INET_ADDRSTRLEN];
-       
-       if(inet_ntop(AF_INET, &pSockaddr4->sin_addr, addrBuf, sizeof(addrBuf)) == NULL)
-       {
-               [NSException raise:NSInternalInconsistencyException format:@"Cannot convert address to string."];
-       }
-       
-       return [NSString stringWithCString:addrBuf encoding:NSASCIIStringEncoding];
-}
-
-- (NSString *)addressHost6:(struct sockaddr_in6 *)pSockaddr6
-{
-       char addrBuf[INET6_ADDRSTRLEN];
-       
-       if(inet_ntop(AF_INET6, &pSockaddr6->sin6_addr, addrBuf, sizeof(addrBuf)) == NULL)
-       {
-               [NSException raise:NSInternalInconsistencyException format:@"Cannot convert address to string."];
-       }
-       
-       return [NSString stringWithCString:addrBuf encoding:NSASCIIStringEncoding];
-}
-
-- (NSString *)addressHost:(struct sockaddr *)pSockaddr
-{
-       if(pSockaddr->sa_family == AF_INET)
-       {
-               return [self addressHost4:(struct sockaddr_in *)pSockaddr];
-       }
-       else
-       {
-               return [self addressHost6:(struct sockaddr_in6 *)pSockaddr];
-       }
-}
-
-////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-#pragma mark Socket Implementation:
-////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-
-/**
- * Binds the underlying socket(s) to the given port.
- * The socket(s) will be able to receive data on any interface.
- * 
- * On success, returns YES.
- * Otherwise returns NO, and sets errPtr. If you don't care about the error, you can pass nil for errPtr.
-**/
-- (BOOL)bindToPort:(UInt16)port error:(NSError **)errPtr
-{
-       return [self bindToAddress:nil port:port error:errPtr];
-}
-
-/**
- * Binds the underlying socket(s) to the given address and port.
- * The sockets(s) will be able to receive data only on the given interface.
- * 
- * To receive data on any interface, pass nil or "".
- * To receive data only on the loopback interface, pass "localhost" or "loopback".
- * 
- * On success, returns YES.
- * Otherwise returns NO, and sets errPtr. If you don't care about the error, you can pass nil for errPtr.
-**/
-- (BOOL)bindToAddress:(NSString *)host port:(UInt16)port error:(NSError **)errPtr
-{
-       if(theFlags & kDidClose)
-       {
-               [NSException raise:AsyncUdpSocketException
-                           format:@"The socket is closed."];
-       }
-       if(theFlags & kDidBind)
-       {
-               [NSException raise:AsyncUdpSocketException
-                           format:@"Cannot bind a socket more than once."];
-       }
-       if(theFlags & kDidConnect)
-       {
-               [NSException raise:AsyncUdpSocketException
-                           format:@"Cannot bind after connecting. If needed, bind first, then connect."];
-       }
-       
-       // Convert the given host/port into native address structures for CFSocketSetAddress
-       NSData *address4 = nil, *address6 = nil;
-       
-       int gai_error = [self convertForBindHost:host port:port intoAddress4:&address4 address6:&address6];
-       if(gai_error)
-       {
-               if(errPtr)
-               {
-                       NSString *errMsg = [NSString stringWithCString:gai_strerror(gai_error) encoding:NSASCIIStringEncoding];
-                       NSDictionary *info = [NSDictionary dictionaryWithObject:errMsg forKey:NSLocalizedDescriptionKey];
-                       
-                       *errPtr = [NSError errorWithDomain:@"kCFStreamErrorDomainNetDB" code:gai_error userInfo:info];
-               }
-               return NO;
-       }
-       
-       NSAssert((address4 || address6), @"address4 and address6 are nil");
-       
-       // Set the SO_REUSEADDR flags
-       
-       int reuseOn = 1;
-       if (theSocket4) setsockopt(CFSocketGetNative(theSocket4), SOL_SOCKET, SO_REUSEADDR, &reuseOn, sizeof(reuseOn));
-       if (theSocket6) setsockopt(CFSocketGetNative(theSocket6), SOL_SOCKET, SO_REUSEADDR, &reuseOn, sizeof(reuseOn));
-       
-       // Bind the sockets
-       
-       if(address4)
-       {
-               if(theSocket4)
-               {
-                       CFSocketError error = CFSocketSetAddress(theSocket4, (CFDataRef)address4);
-                       if(error != kCFSocketSuccess)
-                       {
-                               if(errPtr) *errPtr = [self getSocketError];
-                               return NO;
-                       }
-                       
-                       if(!address6)
-                       {
-                               // Using IPv4 only
-                               [self closeSocket6];
-                       }
-               }
-               else if(!address6)
-               {
-                       if(errPtr) *errPtr = [self getIPv4UnavailableError];
-                       return NO;
-               }
-       }
-       
-       if(address6)
-       {
-               // Note: The iPhone doesn't currently support IPv6
-               
-               if(theSocket6)
-               {
-                       CFSocketError error = CFSocketSetAddress(theSocket6, (CFDataRef)address6);
-                       if(error != kCFSocketSuccess)
-                       {
-                               if(errPtr) *errPtr = [self getSocketError];
-                               return NO;
-                       }
-                       
-                       if(!address4)
-                       {
-                               // Using IPv6 only
-                               [self closeSocket4];
-                       }
-               }
-               else if(!address4)
-               {
-                       if(errPtr) *errPtr = [self getIPv6UnavailableError];
-                       return NO;
-               }
-       }
-       
-       theFlags |= kDidBind;
-       return YES;
-}
-
-/**
- * Connects the underlying UDP socket to the given host and port.
- * If an IPv4 address is resolved, the IPv4 socket is connected, and the IPv6 socket is invalidated and released.
- * If an IPv6 address is resolved, the IPv6 socket is connected, and the IPv4 socket is invalidated and released.
- * 
- * On success, returns YES.
- * Otherwise returns NO, and sets errPtr. If you don't care about the error, you can pass nil for errPtr.
-**/
-- (BOOL)connectToHost:(NSString *)host onPort:(UInt16)port error:(NSError **)errPtr
-{
-       if(theFlags & kDidClose)
-       {
-               [NSException raise:AsyncUdpSocketException
-                           format:@"The socket is closed."];
-       }
-       if(theFlags & kDidConnect)
-       {
-               [NSException raise:AsyncUdpSocketException
-                           format:@"Cannot connect a socket more than once."];
-       }
-       
-       // Convert the given host/port into native address structures for CFSocketSetAddress
-       NSData *address4 = nil, *address6 = nil;
-       
-       int error = [self convertForSendHost:host port:port intoAddress4:&address4 address6:&address6];
-       if(error)
-       {
-               if(errPtr)
-               {
-                       NSString *errMsg = [NSString stringWithCString:gai_strerror(error) encoding:NSASCIIStringEncoding];
-                       NSDictionary *info = [NSDictionary dictionaryWithObject:errMsg forKey:NSLocalizedDescriptionKey];
-                       
-                       *errPtr = [NSError errorWithDomain:@"kCFStreamErrorDomainNetDB" code:error userInfo:info];
-               }
-               return NO;
-       }
-       
-       NSAssert((address4 || address6), @"address4 and address6 are nil");
-       
-       // We only want to connect via a single interface.
-       // IPv4 is currently preferred, but this may change in the future.
-       
-       if(address4)
-       {
-               if(theSocket4)
-               {
-                       CFSocketError sockErr = CFSocketConnectToAddress(theSocket4, (CFDataRef)address4, (CFTimeInterval)0.0);
-                       if(sockErr != kCFSocketSuccess)
-                       {
-                               if(errPtr) *errPtr = [self getSocketError];
-                               return NO;
-                       }
-                       theFlags |= kDidConnect;
-                       
-                       // We're connected to an IPv4 address, so no need for the IPv6 socket
-                       [self closeSocket6];
-                       
-                       return YES;
-               }
-               else if(!address6)
-               {
-                       if(errPtr) *errPtr = [self getIPv4UnavailableError];
-                       return NO;
-               }
-       }
-       
-       if(address6)
-       {
-               // Note: The iPhone doesn't currently support IPv6
-               
-               if(theSocket6)
-               {
-                       CFSocketError sockErr = CFSocketConnectToAddress(theSocket6, (CFDataRef)address6, (CFTimeInterval)0.0);
-                       if(sockErr != kCFSocketSuccess)
-                       {
-                               if(errPtr) *errPtr = [self getSocketError];
-                               return NO;
-                       }
-                       theFlags |= kDidConnect;
-                       
-                       // We're connected to an IPv6 address, so no need for the IPv4 socket
-                       [self closeSocket4];
-                       
-                       return YES;
-               }
-               else
-               {
-                       if(errPtr) *errPtr = [self getIPv6UnavailableError];
-                       return NO;
-               }
-       }
-       
-       // It shouldn't be possible to get to this point because either address4 or address6 was non-nil.
-       if(errPtr) *errPtr = nil;
-       return NO;
-}
-
-/**
- * Connects the underlying UDP socket to the remote address.
- * If the address is an IPv4 address, the IPv4 socket is connected, and the IPv6 socket is invalidated and released.
- * If the address is an IPv6 address, the IPv6 socket is connected, and the IPv4 socket is invalidated and released.
- * 
- * The address is a native address structure, as may be returned from API's such as Bonjour.
- * An address may be created manually by simply wrapping a sockaddr_in or sockaddr_in6 in an NSData object.
- * 
- * On success, returns YES.
- * Otherwise returns NO, and sets errPtr. If you don't care about the error, you can pass nil for errPtr.
-**/
-- (BOOL)connectToAddress:(NSData *)remoteAddr error:(NSError **)errPtr
-{
-       if(theFlags & kDidClose)
-       {
-               [NSException raise:AsyncUdpSocketException
-                           format:@"The socket is closed."];
-       }
-       if(theFlags & kDidConnect)
-       {
-               [NSException raise:AsyncUdpSocketException
-                           format:@"Cannot connect a socket more than once."];
-       }
-       
-       // Is remoteAddr an IPv4 address?
-       if([remoteAddr length] == sizeof(struct sockaddr_in))
-       {
-               if(theSocket4)
-               {
-                       CFSocketError error = CFSocketConnectToAddress(theSocket4, (CFDataRef)remoteAddr, (CFTimeInterval)0.0);
-                       if(error != kCFSocketSuccess)
-                       {
-                               if(errPtr) *errPtr = [self getSocketError];
-                               return NO;
-                       }
-                       theFlags |= kDidConnect;
-                       
-                       // We're connected to an IPv4 address, so no need for the IPv6 socket
-                       [self closeSocket6];
-                       
-                       return YES;
-               }
-               else
-               {
-                       if(errPtr) *errPtr = [self getIPv4UnavailableError];
-                       return NO;
-               }
-       }
-       
-       // Is remoteAddr an IPv6 address?
-       if([remoteAddr length] == sizeof(struct sockaddr_in6))
-       {
-               if(theSocket6)
-               {
-                       CFSocketError error = CFSocketConnectToAddress(theSocket6, (CFDataRef)remoteAddr, (CFTimeInterval)0.0);
-                       if(error != kCFSocketSuccess)
-                       {
-                               if(errPtr) *errPtr = [self getSocketError];
-                               return NO;
-                       }
-                       theFlags |= kDidConnect;
-                       
-                       // We're connected to an IPv6 address, so no need for the IPv4 socket
-                       [self closeSocket4];
-                       
-                       return YES;
-               }
-               else
-               {
-                       if(errPtr) *errPtr = [self getIPv6UnavailableError];
-                       return NO;
-               }
-       }
-       
-       // The remoteAddr was invalid
-       if(errPtr)
-       {
-               NSString *errMsg = @"remoteAddr parameter is not a valid address";
-               NSDictionary *info = [NSDictionary dictionaryWithObject:errMsg forKey:NSLocalizedDescriptionKey];
-               
-               *errPtr = [NSError errorWithDomain:AsyncUdpSocketErrorDomain
-                                                                         code:AsyncUdpSocketBadParameter
-                                                                 userInfo:info];
-       }
-       return NO;
-}
-
-/**
- * Join multicast group
- *
- * Group should be a multicast IP address (eg. @"239.255.250.250" for IPv4).
- * Address is local interface for IPv4, but currently defaults under IPv6.
-**/
-- (BOOL)joinMulticastGroup:(NSString *)group error:(NSError **)errPtr
-{
-       return [self joinMulticastGroup:group withAddress:nil error:errPtr];
-}
-
-- (BOOL)joinMulticastGroup:(NSString *)group withAddress:(NSString *)address error:(NSError **)errPtr
-{
-       if(theFlags & kDidClose)
-       {
-               [NSException raise:AsyncUdpSocketException
-                           format:@"The socket is closed."];
-       }
-       if(!(theFlags & kDidBind))
-       {
-               [NSException raise:AsyncUdpSocketException
-                           format:@"Must bind a socket before joining a multicast group."];
-       }
-       if(theFlags & kDidConnect)
-       {
-               [NSException raise:AsyncUdpSocketException
-                           format:@"Cannot join a multicast group if connected."];
-       }
-       
-       // Get local interface address
-       // Convert the given host/port into native address structures for CFSocketSetAddress
-       NSData *address4 = nil, *address6 = nil;
-       
-       int error = [self convertForBindHost:address port:0 intoAddress4:&address4 address6:&address6];
-       if(error)
-       {
-               if(errPtr)
-               {
-                       NSString *errMsg = [NSString stringWithCString:gai_strerror(error) encoding:NSASCIIStringEncoding];
-                       NSString *errDsc = [NSString stringWithFormat:@"Invalid parameter 'address': %@", errMsg];
-                       NSDictionary *info = [NSDictionary dictionaryWithObject:errDsc forKey:NSLocalizedDescriptionKey];
-                       
-                       *errPtr = [NSError errorWithDomain:@"kCFStreamErrorDomainNetDB" code:error userInfo:info];
-               }
-               return NO;
-       }
-       
-       NSAssert((address4 || address6), @"address4 and address6 are nil");
-       
-       // Get multicast address (group)
-       NSData *group4 = nil, *group6 = nil;
-
-       error = [self convertForBindHost:group port:0 intoAddress4:&group4 address6:&group6];
-       if(error)
-       {
-               if(errPtr)
-               {
-                       NSString *errMsg = [NSString stringWithCString:gai_strerror(error) encoding:NSASCIIStringEncoding];
-                       NSString *errDsc = [NSString stringWithFormat:@"Invalid parameter 'group': %@", errMsg];
-                       NSDictionary *info = [NSDictionary dictionaryWithObject:errDsc forKey:NSLocalizedDescriptionKey];
-                       
-                       *errPtr = [NSError errorWithDomain:@"kCFStreamErrorDomainNetDB" code:error userInfo:info];
-               }
-               return NO;
-       }
-       
-       NSAssert((group4 || group6), @"group4 and group6 are nil");
-       
-       if(theSocket4 && group4 && address4)
-       {
-               const struct sockaddr_in* nativeAddress = [address4 bytes];
-               const struct sockaddr_in* nativeGroup = [group4 bytes];
-               
-               struct ip_mreq imreq;
-               imreq.imr_multiaddr = nativeGroup->sin_addr;
-               imreq.imr_interface = nativeAddress->sin_addr;
-               
-               // JOIN multicast group on default interface
-               error = setsockopt(CFSocketGetNative(theSocket4), IPPROTO_IP, IP_ADD_MEMBERSHIP, 
-                                                  (const void *)&imreq, sizeof(struct ip_mreq));
-               if(error)
-               {
-                       if(errPtr)
-                       {
-                               NSString *errMsg = @"Unable to join IPv4 multicast group";
-                               NSDictionary *info = [NSDictionary dictionaryWithObject:errMsg forKey:NSLocalizedDescriptionKey];
-                               
-                               *errPtr = [NSError errorWithDomain:@"kCFStreamErrorDomainPOSIX" code:error userInfo:info];
-                       }
-                       return NO;
-               }
-               
-               // Using IPv4 only
-               [self closeSocket6];
-               
-               return YES;
-       }
-       
-       if(theSocket6 && group6 && address6)
-       {
-               const struct sockaddr_in6* nativeGroup = [group6 bytes];
-               
-               struct ipv6_mreq imreq;
-               imreq.ipv6mr_multiaddr = nativeGroup->sin6_addr;
-               imreq.ipv6mr_interface = 0;
-               
-               // JOIN multicast group on default interface
-               error = setsockopt(CFSocketGetNative(theSocket6), IPPROTO_IP, IPV6_JOIN_GROUP, 
-                                                  (const void *)&imreq, sizeof(struct ipv6_mreq));
-               if(error)
-               {
-                       if(errPtr)
-                       {
-                               NSString *errMsg = @"Unable to join IPv6 multicast group";
-                               NSDictionary *info = [NSDictionary dictionaryWithObject:errMsg forKey:NSLocalizedDescriptionKey];
-                               
-                               *errPtr = [NSError errorWithDomain:@"kCFStreamErrorDomainPOSIX" code:error userInfo:info];
-                       }
-                       return NO;
-               }
-               
-               // Using IPv6 only
-               [self closeSocket4];
-               
-               return YES;
-       }
-       
-       // The given address and group didn't match the existing socket(s).
-       // This means there were no compatible combination of all IPv4 or IPv6 socket, group and address.
-       if(errPtr)
-       {
-               NSString *errMsg = @"Invalid group and/or address, not matching existing socket(s)";
-               NSDictionary *info = [NSDictionary dictionaryWithObject:errMsg forKey:NSLocalizedDescriptionKey];
-               
-               *errPtr = [NSError errorWithDomain:AsyncUdpSocketErrorDomain
-                                             code:AsyncUdpSocketBadParameter
-                                         userInfo:info];
-       }
-       return NO;
-}
-
-/**
- * By default, the underlying socket in the OS will not allow you to send broadcast messages.
- * In order to send broadcast messages, you need to enable this functionality in the socket.
- * 
- * A broadcast is a UDP message to addresses like "192.168.255.255" or "255.255.255.255" that is
- * delivered to every host on the network.
- * The reason this is generally disabled by default is to prevent
- * accidental broadcast messages from flooding the network.
-**/
-- (BOOL)enableBroadcast:(BOOL)flag error:(NSError **)errPtr
-{
-       if (theSocket4)
-       {
-               int value = flag ? 1 : 0;
-               int error = setsockopt(CFSocketGetNative(theSocket4), SOL_SOCKET, SO_BROADCAST,
-                                                  (const void *)&value, sizeof(value));
-               if(error)
-               {
-                       if(errPtr)
-                       {
-                               NSString *errMsg = @"Unable to enable broadcast message sending";
-                               NSDictionary *info = [NSDictionary dictionaryWithObject:errMsg forKey:NSLocalizedDescriptionKey];
-                               
-                               *errPtr = [NSError errorWithDomain:@"kCFStreamErrorDomainPOSIX" code:error userInfo:info];
-                       }
-                       return NO;
-               }
-       }
-       
-       // IPv6 does not implement broadcast, the ability to send a packet to all hosts on the attached link.
-       // The same effect can be achieved by sending a packet to the link-local all hosts multicast group.
-       
-       return YES;
-}
-
-////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-#pragma mark Disconnect Implementation:
-////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-
-- (void)emptyQueues
-{
-       if (theCurrentSend)     [self endCurrentSend];
-       if (theCurrentReceive)  [self endCurrentReceive];
-       
-       [theSendQueue removeAllObjects];
-       [theReceiveQueue removeAllObjects];
-       
-       [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(maybeDequeueSend) object:nil];
-       [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(maybeDequeueReceive) object:nil];
-       
-       theFlags &= ~kDequeueSendScheduled;
-       theFlags &= ~kDequeueReceiveScheduled;
-}
-
-- (void)closeSocket4
-{
-       if (theSocket4 != NULL)
-       {
-               CFSocketInvalidate(theSocket4);
-               CFRelease(theSocket4);
-               theSocket4 = NULL;
-       }
-       if (theSource4 != NULL)
-       {
-               [self runLoopRemoveSource:theSource4];
-               CFRelease(theSource4);
-               theSource4 = NULL;
-       }
-}
-
-- (void)closeSocket6
-{
-       if (theSocket6 != NULL)
-       {
-               CFSocketInvalidate(theSocket6);
-               CFRelease(theSocket6);
-               theSocket6 = NULL;
-       }
-       if (theSource6 != NULL)
-       {
-               [self runLoopRemoveSource:theSource6];
-               CFRelease(theSource6);
-               theSource6 = NULL;
-       }
-}
-
-- (void)close
-{
-       [self emptyQueues];
-       [self closeSocket4];
-       [self closeSocket6];
-       
-       theRunLoop = NULL;
-       
-       // Delay notification to give user freedom to release without returning here and core-dumping.
-       if ([theDelegate respondsToSelector:@selector(onUdpSocketDidClose:)])
-       {
-               [theDelegate performSelector:@selector(onUdpSocketDidClose:)
-                                                 withObject:self
-                                                 afterDelay:0
-                                                        inModes:theRunLoopModes];
-       }
-       
-       theFlags |= kDidClose;
-}
-
-- (void)closeAfterSending
-{
-       if(theFlags & kDidClose) return;
-       
-       theFlags |= (kForbidSendReceive | kCloseAfterSends);
-       [self maybeScheduleClose];
-}
-
-- (void)closeAfterReceiving
-{
-       if(theFlags & kDidClose) return;
-       
-       theFlags |= (kForbidSendReceive | kCloseAfterReceives);
-       [self maybeScheduleClose];
-}
-
-- (void)closeAfterSendingAndReceiving
-{
-       if(theFlags & kDidClose) return;
-       
-       theFlags |= (kForbidSendReceive | kCloseAfterSends | kCloseAfterReceives);
-       [self maybeScheduleClose];
-}
-
-- (void)maybeScheduleClose
-{
-       BOOL shouldDisconnect = NO;
-       
-       if(theFlags & kCloseAfterSends)
-       {
-               if(([theSendQueue count] == 0) && (theCurrentSend == nil))
-               {
-                       if(theFlags & kCloseAfterReceives)
-                       {
-                               if(([theReceiveQueue count] == 0) && (theCurrentReceive == nil))
-                               {
-                                       shouldDisconnect = YES;
-                               }
-                       }
-                       else
-                       {
-                               shouldDisconnect = YES;
-                       }
-               }
-       }
-       else if(theFlags & kCloseAfterReceives)
-       {
-               if(([theReceiveQueue count] == 0) && (theCurrentReceive == nil))
-               {
-                       shouldDisconnect = YES;
-               }
-       }
-       
-       if(shouldDisconnect)
-       {
-               [self performSelector:@selector(close) withObject:nil afterDelay:0 inModes:theRunLoopModes];
-       }
-}
-
-////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-#pragma mark Errors
-////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-
-/**
- * Returns a standard error object for the current errno value.
- * Errno is used for low-level BSD socket errors.
-**/
-- (NSError *)getErrnoError
-{
-       NSString *errorMsg = [NSString stringWithUTF8String:strerror(errno)];
-       NSDictionary *userInfo = [NSDictionary dictionaryWithObject:errorMsg forKey:NSLocalizedDescriptionKey];
-       
-       return [NSError errorWithDomain:NSPOSIXErrorDomain code:errno userInfo:userInfo];
-}
-
-/**
- * Returns a standard error message for a CFSocket error.
- * Unfortunately, CFSocket offers no feedback on its errors.
-**/
-- (NSError *)getSocketError
-{
-       NSString *errMsg = @"General CFSocket error";
-       NSDictionary *info = [NSDictionary dictionaryWithObject:errMsg forKey:NSLocalizedDescriptionKey];
-       
-       return [NSError errorWithDomain:AsyncUdpSocketErrorDomain code:AsyncUdpSocketCFSocketError userInfo:info];
-}
-
-- (NSError *)getIPv4UnavailableError
-{
-       NSString *errMsg = @"IPv4 is unavailable due to binding/connecting using IPv6 only";
-       NSDictionary *info = [NSDictionary dictionaryWithObject:errMsg forKey:NSLocalizedDescriptionKey];
-       
-       return [NSError errorWithDomain:AsyncUdpSocketErrorDomain code:AsyncUdpSocketIPv4Unavailable userInfo:info];
-}
-
-- (NSError *)getIPv6UnavailableError
-{
-       NSString *errMsg = @"IPv6 is unavailable due to binding/connecting using IPv4 only or is not supported on this platform";
-       NSDictionary *info = [NSDictionary dictionaryWithObject:errMsg forKey:NSLocalizedDescriptionKey];
-       
-       return [NSError errorWithDomain:AsyncUdpSocketErrorDomain code:AsyncUdpSocketIPv6Unavailable userInfo:info];
-}
-
-- (NSError *)getSendTimeoutError
-{
-       NSString *errMsg = @"Send operation timed out";
-       NSDictionary *info = [NSDictionary dictionaryWithObject:errMsg forKey:NSLocalizedDescriptionKey];
-       
-       return [NSError errorWithDomain:AsyncUdpSocketErrorDomain code:AsyncUdpSocketSendTimeoutError userInfo:info];
-}
-- (NSError *)getReceiveTimeoutError
-{
-       NSString *errMsg = @"Receive operation timed out";
-       NSDictionary *info = [NSDictionary dictionaryWithObject:errMsg forKey:NSLocalizedDescriptionKey];
-       
-       return [NSError errorWithDomain:AsyncUdpSocketErrorDomain code:AsyncUdpSocketReceiveTimeoutError userInfo:info];
-}
-
-////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-#pragma mark Diagnostics
-////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-
-- (NSString *)localHost
-{
-       if(cachedLocalHost) return cachedLocalHost;
-       
-       if(theSocket4)
-               return [self localHost:theSocket4];
-       else
-               return [self localHost:theSocket6];
-}
-
-- (UInt16)localPort
-{
-       if(cachedLocalPort > 0) return cachedLocalPort;
-       
-       if(theSocket4)
-               return [self localPort:theSocket4];
-       else
-               return [self localPort:theSocket6];
-}
-
-- (NSString *)connectedHost
-{
-       if(cachedConnectedHost) return cachedConnectedHost;
-       
-       if(theSocket4)
-               return [self connectedHost:theSocket4];
-       else
-               return [self connectedHost:theSocket6];
-}
-
-- (UInt16)connectedPort
-{
-       if(cachedConnectedPort > 0) return cachedConnectedPort;
-       
-       if(theSocket4)
-               return [self connectedPort:theSocket4];
-       else
-               return [self connectedPort:theSocket6];
-}
-
-- (NSString *)localHost:(CFSocketRef)theSocket
-{
-       if(theSocket == NULL) return nil;
-       
-       // Unfortunately we can't use CFSocketCopyAddress.
-       // The CFSocket library caches the address the first time you call CFSocketCopyAddress.
-       // So if this is called prior to binding/connecting/sending, it won't be updated again when necessary,
-       // and will continue to return the old value of the socket address.
-       
-       NSString *result = nil;
-       
-       if(theSocket == theSocket4)
-       {
-               struct sockaddr_in sockaddr4;
-               socklen_t sockaddr4len = sizeof(sockaddr4);
-               
-               if(getsockname(CFSocketGetNative(theSocket), (struct sockaddr *)&sockaddr4, &sockaddr4len) < 0)
-               {
-                       return nil;
-               }
-               result = [self addressHost4:&sockaddr4];
-       }
-       else
-       {
-               struct sockaddr_in6 sockaddr6;
-               socklen_t sockaddr6len = sizeof(sockaddr6);
-               
-               if(getsockname(CFSocketGetNative(theSocket), (struct sockaddr *)&sockaddr6, &sockaddr6len) < 0)
-               {
-                       return nil;
-               }
-               result = [self addressHost6:&sockaddr6];
-       }
-       
-       if(theFlags & kDidBind)
-       {
-               [cachedLocalHost release];
-               cachedLocalHost = [result copy];
-       }
-       
-       return result;
-}
-
-- (UInt16)localPort:(CFSocketRef)theSocket
-{
-       if(theSocket == NULL) return 0;
-       
-       // Unfortunately we can't use CFSocketCopyAddress.
-       // The CFSocket library caches the address the first time you call CFSocketCopyAddress.
-       // So if this is called prior to binding/connecting/sending, it won't be updated again when necessary,
-       // and will continue to return the old value of the socket address.
-       
-       UInt16 result = 0;
-       
-       if(theSocket == theSocket4)
-       {
-               struct sockaddr_in sockaddr4;
-               socklen_t sockaddr4len = sizeof(sockaddr4);
-               
-               if(getsockname(CFSocketGetNative(theSocket), (struct sockaddr *)&sockaddr4, &sockaddr4len) < 0)
-               {
-                       return 0;
-               }
-               result = ntohs(sockaddr4.sin_port);
-       }
-       else
-       {
-               struct sockaddr_in6 sockaddr6;
-               socklen_t sockaddr6len = sizeof(sockaddr6);
-               
-               if(getsockname(CFSocketGetNative(theSocket), (struct sockaddr *)&sockaddr6, &sockaddr6len) < 0)
-               {
-                       return 0;
-               }
-               result = ntohs(sockaddr6.sin6_port);
-       }
-       
-       if(theFlags & kDidBind)
-       {
-               cachedLocalPort = result;
-       }
-       
-       return result;
-}
-
-- (NSString *)connectedHost:(CFSocketRef)theSocket
-{
-       if(theSocket == NULL) return nil;
-       
-       // Unfortunately we can't use CFSocketCopyPeerAddress.
-       // The CFSocket library caches the address the first time you call CFSocketCopyPeerAddress.
-       // So if this is called prior to binding/connecting/sending, it may not be updated again when necessary,
-       // and will continue to return the old value of the socket peer address.
-       
-       NSString *result = nil;
-       
-       if(theSocket == theSocket4)
-       {
-               struct sockaddr_in sockaddr4;
-               socklen_t sockaddr4len = sizeof(sockaddr4);
-               
-               if(getpeername(CFSocketGetNative(theSocket), (struct sockaddr *)&sockaddr4, &sockaddr4len) < 0)
-               {
-                       return nil;
-               }
-               result = [self addressHost4:&sockaddr4];
-       }
-       else
-       {
-               struct sockaddr_in6 sockaddr6;
-               socklen_t sockaddr6len = sizeof(sockaddr6);
-               
-               if(getpeername(CFSocketGetNative(theSocket), (struct sockaddr *)&sockaddr6, &sockaddr6len) < 0)
-               {
-                       return nil;
-               }
-               result = [self addressHost6:&sockaddr6];
-       }
-       
-       if(theFlags & kDidConnect)
-       {
-               [cachedConnectedHost release];
-               cachedConnectedHost = [result copy];
-       }
-       
-       return result;
-}
-
-- (UInt16)connectedPort:(CFSocketRef)theSocket
-{
-       if(theSocket == NULL) return 0;
-       
-       // Unfortunately we can't use CFSocketCopyPeerAddress.
-       // The CFSocket library caches the address the first time you call CFSocketCopyPeerAddress.
-       // So if this is called prior to binding/connecting/sending, it may not be updated again when necessary,
-       // and will continue to return the old value of the socket peer address.
-       
-       UInt16 result = 0;
-       
-       if(theSocket == theSocket4)
-       {
-               struct sockaddr_in sockaddr4;
-               socklen_t sockaddr4len = sizeof(sockaddr4);
-               
-               if(getpeername(CFSocketGetNative(theSocket), (struct sockaddr *)&sockaddr4, &sockaddr4len) < 0)
-               {
-                       return 0;
-               }
-               result = ntohs(sockaddr4.sin_port);
-       }
-       else
-       {
-               struct sockaddr_in6 sockaddr6;
-               socklen_t sockaddr6len = sizeof(sockaddr6);
-               
-               if(getpeername(CFSocketGetNative(theSocket), (struct sockaddr *)&sockaddr6, &sockaddr6len) < 0)
-               {
-                       return 0;
-               }
-               result = ntohs(sockaddr6.sin6_port);
-       }
-       
-       if(theFlags & kDidConnect)
-       {
-               cachedConnectedPort = result;
-       }
-       
-       return result;
-}
-
-- (BOOL)isConnected
-{
-       return (((theFlags & kDidConnect) != 0) && ((theFlags & kDidClose) == 0));
-}
-
-- (BOOL)isConnectedToHost:(NSString *)host port:(UInt16)port
-{
-       return [[self connectedHost] isEqualToString:host] && ([self connectedPort] == port);
-}
-
-- (BOOL)isClosed
-{
-       return (theFlags & kDidClose) ? YES : NO;
-}
-
-- (BOOL)isIPv4
-{
-       return (theSocket4 != NULL);
-}
-
-- (BOOL)isIPv6
-{
-       return (theSocket6 != NULL);
-}
-
-- (unsigned int)maximumTransmissionUnit
-{
-       CFSocketNativeHandle theNativeSocket;
-       if(theSocket4)
-               theNativeSocket = CFSocketGetNative(theSocket4);
-       else if(theSocket6)
-               theNativeSocket = CFSocketGetNative(theSocket6);
-       else
-               return 0;
-       
-       if(theNativeSocket == 0)
-       {
-               return 0;
-       }
-       
-       struct ifreq ifr;
-       bzero(&ifr, sizeof(ifr));
-       
-       if(if_indextoname(theNativeSocket, ifr.ifr_name) == NULL)
-       {
-               return 0;
-       }
-       
-       if(ioctl(theNativeSocket, SIOCGIFMTU, &ifr) >= 0)
-       {
-               return ifr.ifr_mtu;
-       }
-       
-       return 0;
-}
-
-////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-#pragma mark Sending
-////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-
-- (BOOL)sendData:(NSData *)data withTimeout:(NSTimeInterval)timeout tag:(long)tag
-{
-       if((data == nil) || ([data length] == 0)) return NO;
-       if(theFlags & kForbidSendReceive) return NO;
-       if(theFlags & kDidClose) return NO;
-       
-       // This method is only for connected sockets
-       if(![self isConnected]) return NO;
-       
-       AsyncSendPacket *packet = [[AsyncSendPacket alloc] initWithData:data address:nil timeout:timeout tag:tag];
-       
-       [theSendQueue addObject:packet];
-       [self scheduleDequeueSend];
-       
-       [packet release];
-       return YES;
-}
-
-- (BOOL)sendData:(NSData *)data toHost:(NSString *)host port:(UInt16)port withTimeout:(NSTimeInterval)timeout tag:(long)tag
-{
-       if((data == nil) || ([data length] == 0)) return NO;
-       if(theFlags & kForbidSendReceive) return NO;
-       if(theFlags & kDidClose) return NO;
-       
-       // This method is only for non-connected sockets
-       if([self isConnected]) return NO;
-       
-       NSData *address4 = nil, *address6 = nil;
-       [self convertForSendHost:host port:port intoAddress4:&address4 address6:&address6];
-       
-       AsyncSendPacket *packet = nil;
-       
-       if(address4 && theSocket4)
-               packet = [[AsyncSendPacket alloc] initWithData:data address:address4 timeout:timeout tag:tag];
-       else if(address6 && theSocket6)
-               packet = [[AsyncSendPacket alloc] initWithData:data address:address6 timeout:timeout tag:tag];
-       else
-               return NO;
-       
-       [theSendQueue addObject:packet];
-       [self scheduleDequeueSend];
-       
-       [packet release];
-       return YES;
-}
-
-- (BOOL)sendData:(NSData *)data toAddress:(NSData *)remoteAddr withTimeout:(NSTimeInterval)timeout tag:(long)tag
-{
-       if((data == nil) || ([data length] == 0)) return NO;
-       if(theFlags & kForbidSendReceive) return NO;
-       if(theFlags & kDidClose) return NO;
-       
-       // This method is only for non-connected sockets
-       if([self isConnected]) return NO;
-       
-       if([remoteAddr length] == sizeof(struct sockaddr_in) && !theSocket4)
-               return NO;
-       
-       if([remoteAddr length] == sizeof(struct sockaddr_in6) && !theSocket6)
-               return NO;
-       
-       AsyncSendPacket *packet = [[AsyncSendPacket alloc] initWithData:data address:remoteAddr timeout:timeout tag:tag];
-       
-       [theSendQueue addObject:packet];
-       [self scheduleDequeueSend];
-       
-       [packet release];
-       return YES;
-}
-
-- (BOOL)canAcceptBytes:(CFSocketRef)sockRef
-{
-       if(sockRef == theSocket4)
-       {
-               if(theFlags & kSock4CanAcceptBytes) return YES;
-       }
-       else
-       {
-               if(theFlags & kSock6CanAcceptBytes) return YES;
-       }
-       
-       CFSocketNativeHandle theNativeSocket = CFSocketGetNative(sockRef);
-       
-       if(theNativeSocket == 0)
-       {
-               NSLog(@"Error - Could not get CFSocketNativeHandle from CFSocketRef");
-               return NO;
-       } 
-       
-       fd_set fds;
-       FD_ZERO(&fds);
-       FD_SET(theNativeSocket, &fds);
-       
-       struct timeval timeout;
-       timeout.tv_sec = 0;
-       timeout.tv_usec = 0;
-       
-       return select(FD_SETSIZE, NULL, &fds, NULL, &timeout) > 0;
-}
-
-- (CFSocketRef)socketForPacket:(AsyncSendPacket *)packet
-{
-       if(!theSocket4)
-               return theSocket6;
-       if(!theSocket6)
-               return theSocket4;
-       
-       return ([packet->address length] == sizeof(struct sockaddr_in)) ? theSocket4 : theSocket6;
-}
-
-/**
- * Puts a maybeDequeueSend on the run loop.
-**/
-- (void)scheduleDequeueSend
-{
-       if((theFlags & kDequeueSendScheduled) == 0)
-       {
-               theFlags |= kDequeueSendScheduled;
-               [self performSelector:@selector(maybeDequeueSend) withObject:nil afterDelay:0 inModes:theRunLoopModes];
-       }
-}
-
-/**
- * This method starts a new send, if needed.
- * It is called when a user requests a send.
-**/
-- (void)maybeDequeueSend
-{
-       // Unset the flag indicating a call to this method is scheduled
-       theFlags &= ~kDequeueSendScheduled;
-       
-       if(theCurrentSend == nil)
-       {
-               if([theSendQueue count] > 0)
-               {
-                       // Dequeue next send packet
-                       theCurrentSend = [[theSendQueue objectAtIndex:0] retain];
-                       [theSendQueue removeObjectAtIndex:0];
-                       
-                       // Start time-out timer.
-                       if(theCurrentSend->timeout >= 0.0)
-                       {
-                               theSendTimer = [NSTimer timerWithTimeInterval:theCurrentSend->timeout
-                                                                                                          target:self 
-                                                                                                        selector:@selector(doSendTimeout:)
-                                                                                                        userInfo:nil
-                                                                                                         repeats:NO];
-                               
-                               [self runLoopAddTimer:theSendTimer];
-                       }
-                       
-                       // Immediately send, if possible.
-                       [self doSend:[self socketForPacket:theCurrentSend]];
-               }
-               else if(theFlags & kCloseAfterSends)
-               {
-                       if(theFlags & kCloseAfterReceives)
-                       {
-                               if(([theReceiveQueue count] == 0) && (theCurrentReceive == nil))
-                               {
-                                       [self close];
-                               }
-                       }
-                       else
-                       {
-                               [self close];
-                       }
-               }
-       }
-}
-
-/**
- * This method is called when a new read is taken from the read queue or when new data becomes available on the stream.
-**/
-- (void)doSend:(CFSocketRef)theSocket
-{
-       if(theCurrentSend != nil)
-       {
-               if(theSocket != [self socketForPacket:theCurrentSend])
-               {
-                       // Current send is for the other socket
-                       return;
-               }
-               
-               if([self canAcceptBytes:theSocket])
-               {
-                       int result;
-                       CFSocketNativeHandle theNativeSocket = CFSocketGetNative(theSocket);
-                       
-                       const void *buf  = [theCurrentSend->buffer bytes];
-                       unsigned bufSize = [theCurrentSend->buffer length];
-                       
-                       if([self isConnected])
-                       {
-                               result = send(theNativeSocket, buf, bufSize, 0);
-                       }
-                       else
-                       {
-                               const void *dst  = [theCurrentSend->address bytes];
-                               unsigned dstSize = [theCurrentSend->address length];
-                               
-                               result = sendto(theNativeSocket, buf, bufSize, 0, dst, dstSize);
-                       }
-                       
-                       if(theSocket == theSocket4)
-                               theFlags &= ~kSock4CanAcceptBytes;
-                       else
-                               theFlags &= ~kSock6CanAcceptBytes;
-                       
-                       if(result < 0)
-                       {
-                               [self failCurrentSend:[self getErrnoError]];
-                       }
-                       else
-                       {
-                               // If it wasn't bound before, it's bound now
-                               theFlags |= kDidBind;
-                               
-                               [self completeCurrentSend];
-                       }
-                       
-                       [self scheduleDequeueSend];
-               }
-               else
-               {
-                       // Request notification when the socket is ready to send more data
-                       CFSocketEnableCallBacks(theSocket, kCFSocketReadCallBack | kCFSocketWriteCallBack);
-               }
-       }
-}
-
-- (void)completeCurrentSend
-{
-       NSAssert (theCurrentSend, @"Trying to complete current send when there is no current send.");
-       
-       if ([theDelegate respondsToSelector:@selector(onUdpSocket:didSendDataWithTag:)])
-       {
-               [theDelegate onUdpSocket:self didSendDataWithTag:theCurrentSend->tag];
-       }
-       
-       if (theCurrentSend != nil) [self endCurrentSend]; // Caller may have disconnected.
-}
-
-- (void)failCurrentSend:(NSError *)error
-{
-       NSAssert (theCurrentSend, @"Trying to fail current send when there is no current send.");
-       
-       if ([theDelegate respondsToSelector:@selector(onUdpSocket:didNotSendDataWithTag:dueToError:)])
-       {
-               [theDelegate onUdpSocket:self didNotSendDataWithTag:theCurrentSend->tag dueToError:error];
-       }
-       
-       if (theCurrentSend != nil) [self endCurrentSend]; // Caller may have disconnected.
-}
-
-/**
- * Ends the current send, and all associated variables such as the send timer.
-**/
-- (void)endCurrentSend
-{
-       NSAssert (theCurrentSend, @"Trying to end current send when there is no current send.");
-       
-       [theSendTimer invalidate];
-       theSendTimer = nil;
-       
-       [theCurrentSend release];
-       theCurrentSend = nil;
-}
-
-- (void)doSendTimeout:(NSTimer *)timer
-{
-       if (timer != theSendTimer) return; // Old timer. Ignore it.
-       if (theCurrentSend != nil)
-       {
-               [self failCurrentSend:[self getSendTimeoutError]];
-               [self scheduleDequeueSend];
-       }
-}
-
-////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-#pragma mark Receiving
-////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-
-- (void)receiveWithTimeout:(NSTimeInterval)timeout tag:(long)tag
-{
-       if(theFlags & kForbidSendReceive) return;
-       if(theFlags & kDidClose) return;
-       
-       AsyncReceivePacket *packet = [[AsyncReceivePacket alloc] initWithTimeout:timeout tag:tag];
-       
-       [theReceiveQueue addObject:packet];
-       [self scheduleDequeueReceive];
-       
-       [packet release];
-}
-
-- (BOOL)hasBytesAvailable:(CFSocketRef)sockRef
-{
-       if(sockRef == theSocket4)
-       {
-               if(theFlags & kSock4HasBytesAvailable) return YES;
-       }
-       else
-       {
-               if(theFlags & kSock6HasBytesAvailable) return YES;
-       }
-       
-       CFSocketNativeHandle theNativeSocket = CFSocketGetNative(sockRef);
-       
-       if(theNativeSocket == 0)
-       {
-               NSLog(@"Error - Could not get CFSocketNativeHandle from CFSocketRef");
-               return NO;
-       } 
-       
-       fd_set fds;
-       FD_ZERO(&fds);
-       FD_SET(theNativeSocket, &fds);
-       
-       struct timeval timeout;
-       timeout.tv_sec = 0;
-       timeout.tv_usec = 0;
-       
-       return select(FD_SETSIZE, &fds, NULL, NULL, &timeout) > 0;
-}
-
-/**
- * Puts a maybeDequeueReceive on the run loop.
-**/
-- (void)scheduleDequeueReceive
-{
-       if((theFlags & kDequeueReceiveScheduled) == 0)
-       {
-               theFlags |= kDequeueReceiveScheduled;
-               [self performSelector:@selector(maybeDequeueReceive) withObject:nil afterDelay:0 inModes:theRunLoopModes];
-       }
-}
-
-/**
- * Starts a new receive operation if needed
-**/
-- (void)maybeDequeueReceive
-{
-       // Unset the flag indicating a call to this method is scheduled
-       theFlags &= ~kDequeueReceiveScheduled;
-       
-       if (theCurrentReceive == nil)
-       {
-               if([theReceiveQueue count] > 0)
-               {
-                       // Dequeue next receive packet
-                       theCurrentReceive = [[theReceiveQueue objectAtIndex:0] retain];
-                       [theReceiveQueue removeObjectAtIndex:0];
-                       
-                       // Start time-out timer.
-                       if (theCurrentReceive->timeout >= 0.0)
-                       {
-                               theReceiveTimer = [NSTimer timerWithTimeInterval:theCurrentReceive->timeout
-                                                                                                                 target:self
-                                                                                                               selector:@selector(doReceiveTimeout:)
-                                                                                                               userInfo:nil
-                                                                                                                repeats:NO];
-                               
-                               [self runLoopAddTimer:theReceiveTimer];
-                       }
-                       
-                       // Immediately receive, if possible
-                       // We always check both sockets so we don't ever starve one of them.
-                       // We also check them in alternating orders to prevent starvation if both of them
-                       // have a continuous flow of incoming data.
-                       if(theFlags & kFlipFlop)
-                       {
-                               [self doReceive4];
-                               [self doReceive6];
-                       }
-                       else
-                       {
-                               [self doReceive6];
-                               [self doReceive4];
-                       }
-                       
-                       theFlags ^= kFlipFlop;
-               }
-               else if(theFlags & kCloseAfterReceives)
-               {
-                       if(theFlags & kCloseAfterSends)
-                       {
-                               if(([theSendQueue count] == 0) && (theCurrentSend == nil))
-                               {
-                                       [self close];
-                               }
-                       }
-                       else
-                       {
-                               [self close];
-                       }
-               }
-       }
-}
-
-- (void)doReceive4
-{
-       if(theSocket4) [self doReceive:theSocket4];
-}
-
-- (void)doReceive6
-{
-       if(theSocket6) [self doReceive:theSocket6];
-}
-
-- (void)doReceive:(CFSocketRef)theSocket
-{
-       if (theCurrentReceive != nil)
-       {
-               BOOL appIgnoredReceivedData;
-               BOOL userIgnoredReceivedData;
-               
-               do
-               {
-                       // Set or reset ignored variables.
-                       // If the app or user ignores the received data, we'll continue this do-while loop.
-                       appIgnoredReceivedData = NO;
-                       userIgnoredReceivedData = NO;
-               
-                       if([self hasBytesAvailable:theSocket])
-                       {
-                               int result;
-                               CFSocketNativeHandle theNativeSocket = CFSocketGetNative(theSocket);
-                               
-                               // Allocate buffer for recvfrom operation.
-                               // If the operation is successful, we'll realloc the buffer to the appropriate size,
-                               // and create an NSData wrapper around it without needing to copy any bytes around.
-                               void *buf = malloc(maxReceiveBufferSize);
-                               size_t bufSize = maxReceiveBufferSize;
-                               
-                               if(theSocket == theSocket4)
-                               {
-                                       struct sockaddr_in sockaddr4;
-                                       socklen_t sockaddr4len = sizeof(sockaddr4);
-                                       
-                                       result = recvfrom(theNativeSocket, buf, bufSize, 0, (struct sockaddr *)&sockaddr4, &sockaddr4len);
-                                       
-                                       if(result >= 0)
-                                       {
-                                               NSString *host = [self addressHost4:&sockaddr4];
-                                               UInt16 port = ntohs(sockaddr4.sin_port);
-                                               
-                                               if([self isConnected] && ![self isConnectedToHost:host port:port])
-                                               {
-                                                       // The user connected to an address, and the received data doesn't match the address.
-                                                       // This may happen if the data is received by the kernel prior to the connect call.
-                                                       appIgnoredReceivedData = YES;
-                                               }
-                                               else
-                                               {
-                                                       if(result != bufSize)
-                                                       {
-                                                               buf = realloc(buf, result);
-                                                       }
-                                                       theCurrentReceive->buffer = [[NSData alloc] initWithBytesNoCopy:buf
-                                                                                                                                                                        length:result
-                                                                                                                                                          freeWhenDone:YES];
-                                                       theCurrentReceive->host = [host retain];
-                                                       theCurrentReceive->port = port;
-                                               }
-                                       }
-                                       
-                                       theFlags &= ~kSock4HasBytesAvailable;
-                               }
-                               else
-                               {
-                                       struct sockaddr_in6 sockaddr6;
-                                       socklen_t sockaddr6len = sizeof(sockaddr6);
-                                       
-                                       result = recvfrom(theNativeSocket, buf, bufSize, 0, (struct sockaddr *)&sockaddr6, &sockaddr6len);
-                                       
-                                       if(result >= 0)
-                                       {
-                                               NSString *host = [self addressHost6:&sockaddr6];
-                                               UInt16 port = ntohs(sockaddr6.sin6_port);
-                                               
-                                               if([self isConnected] && ![self isConnectedToHost:host port:port])
-                                               {
-                                                       // The user connected to an address, and the received data doesn't match the address.
-                                                       // This may happen if the data is received by the kernel prior to the connect call.
-                                                       appIgnoredReceivedData = YES;
-                                               }
-                                               else
-                                               {
-                                                       if(result != bufSize)
-                                                       {
-                                                               buf = realloc(buf, result);
-                                                       }
-                                                       theCurrentReceive->buffer = [[NSData alloc] initWithBytesNoCopy:buf
-                                                                                                                                                                        length:result
-                                                                                                                                                          freeWhenDone:YES];
-                                                       theCurrentReceive->host = [host retain];
-                                                       theCurrentReceive->port = port;
-                                               }
-                                       }
-                                       
-                                       theFlags &= ~kSock6HasBytesAvailable;
-                               }
-                               
-                               // Check to see if we need to free our alloc'd buffer
-                               // If the buffer is non-nil, this means it has taken ownership of the buffer
-                               if(theCurrentReceive->buffer == nil)
-                               {
-                                       free(buf);
-                               }
-                               
-                               if(result < 0)
-                               {
-                                       [self failCurrentReceive:[self getErrnoError]];
-                                       [self scheduleDequeueReceive];
-                               }
-                               else if(!appIgnoredReceivedData)
-                               {
-                                       BOOL finished = [self maybeCompleteCurrentReceive];
-                                       
-                                       if(finished)
-                                       {
-                                               [self scheduleDequeueReceive];
-                                       }
-                                       else
-                                       {
-                                               [theCurrentReceive->buffer release];
-                                               [theCurrentReceive->host release];
-                                               
-                                               theCurrentReceive->buffer = nil;
-                                               theCurrentReceive->host = nil;
-                                               
-                                               userIgnoredReceivedData = YES;
-                                       }
-                               }
-                       }
-                       else
-                       {
-                               // Request notification when the socket is ready to receive more data
-                               CFSocketEnableCallBacks(theSocket, kCFSocketReadCallBack | kCFSocketWriteCallBack);
-                       }
-                       
-               } while(appIgnoredReceivedData || userIgnoredReceivedData);
-       }
-}
-
-- (BOOL)maybeCompleteCurrentReceive
-{
-       NSAssert (theCurrentReceive, @"Trying to complete current receive when there is no current receive.");
-       
-       BOOL finished = YES;
-       
-       if ([theDelegate respondsToSelector:@selector(onUdpSocket:didReceiveData:withTag:fromHost:port:)])
-       {
-               finished = [theDelegate onUdpSocket:self
-                                                        didReceiveData:theCurrentReceive->buffer
-                                                                       withTag:theCurrentReceive->tag
-                                                                  fromHost:theCurrentReceive->host
-                                                                          port:theCurrentReceive->port];
-       }
-       
-       if (finished)
-       {
-               if (theCurrentReceive != nil) [self endCurrentReceive]; // Caller may have disconnected.
-       }
-       return finished;
-}
-
-- (void)failCurrentReceive:(NSError *)error
-{
-       NSAssert (theCurrentReceive, @"Trying to fail current receive when there is no current receive.");
-       
-       if ([theDelegate respondsToSelector:@selector(onUdpSocket:didNotReceiveDataWithTag:dueToError:)])
-       {
-               [theDelegate onUdpSocket:self didNotReceiveDataWithTag:theCurrentReceive->tag dueToError:error];
-       }
-       
-       if (theCurrentReceive != nil) [self endCurrentReceive]; // Caller may have disconnected.
-}
-
-- (void)endCurrentReceive
-{
-       NSAssert (theCurrentReceive, @"Trying to end current receive when there is no current receive.");
-       
-       [theReceiveTimer invalidate];
-       theReceiveTimer = nil;
-       
-       [theCurrentReceive release];
-       theCurrentReceive = nil;
-}
-
-- (void)doReceiveTimeout:(NSTimer *)timer
-{
-       if (timer != theReceiveTimer) return; // Old timer. Ignore it.
-       if (theCurrentReceive != nil)
-       {
-               [self failCurrentReceive:[self getReceiveTimeoutError]];
-               [self scheduleDequeueReceive];
-       }
-}
-
-////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-#pragma mark CF Callbacks
-////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-
-- (void)doCFSocketCallback:(CFSocketCallBackType)type
-                                forSocket:(CFSocketRef)sock
-                          withAddress:(NSData *)address
-                                 withData:(const void *)pData
-{
-       NSParameterAssert((sock == theSocket4) || (sock == theSocket6));
-       
-       switch (type)
-       {
-               case kCFSocketReadCallBack:
-                       if(sock == theSocket4)
-                               theFlags |= kSock4HasBytesAvailable;
-                       else
-                               theFlags |= kSock6HasBytesAvailable;
-                       [self doReceive:sock];
-                       break;
-               case kCFSocketWriteCallBack:
-                       if(sock == theSocket4)
-                               theFlags |= kSock4CanAcceptBytes;
-                       else
-                               theFlags |= kSock6CanAcceptBytes;
-                       [self doSend:sock];
-                       break;
-               default:
-                       NSLog (@"AsyncUdpSocket %p received unexpected CFSocketCallBackType %d.", self, type);
-                       break;
-       }
-}
-
-/**
- * This is the callback we setup for CFSocket.
- * This method does nothing but forward the call to it's Objective-C counterpart
-**/
-static void MyCFSocketCallback(CFSocketRef sref, CFSocketCallBackType type, CFDataRef address, const void *pData, void *pInfo)
-{
-       NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
-       
-       AsyncUdpSocket *theSocket = [[(AsyncUdpSocket *)pInfo retain] autorelease];
-       [theSocket doCFSocketCallback:type forSocket:sref withAddress:(NSData *)address withData:pData];
-       
-       [pool release];
-}
-
-@end