Guest User

Untitled

a guest
Jun 27th, 2013
286
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 65.58 KB | None | 0 0
  1. //
  2. // AsyncUdpSocket.m
  3. //
  4. // This class is in the public domain.
  5. // Originally created by Robbie Hanson on Wed Oct 01 2008.
  6. // Updated and maintained by Deusty Designs and the Mac development community.
  7. //
  8. // http://code.google.com/p/cocoaasyncsocket/
  9. //
  10.  
  11. #if ! __has_feature(objc_arc)
  12. #warning This file must be compiled with ARC. Use -fobjc-arc flag (or convert project to ARC).
  13. #endif
  14.  
  15. #import "AsyncUdpSocket.h"
  16. #import <sys/socket.h>
  17. #import <netinet/in.h>
  18. #import <arpa/inet.h>
  19. #import <sys/ioctl.h>
  20. #import <net/if.h>
  21. #import <netdb.h>
  22.  
  23. #if TARGET_OS_IPHONE
  24. // Note: You may need to add the CFNetwork Framework to your project
  25. #import <CFNetwork/CFNetwork.h>
  26. #endif
  27.  
  28.  
  29. #define SENDQUEUE_CAPACITY 5 // Initial capacity
  30. #define RECEIVEQUEUE_CAPACITY 5 // Initial capacity
  31.  
  32. #define DEFAULT_MAX_RECEIVE_BUFFER_SIZE 9216
  33.  
  34. NSString *const AsyncUdpSocketException = @"AsyncUdpSocketException";
  35. NSString *const AsyncUdpSocketErrorDomain = @"AsyncUdpSocketErrorDomain";
  36.  
  37. #if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5
  38. // Mutex lock used by all instances of AsyncUdpSocket, to protect getaddrinfo.
  39. // Prior to Mac OS X 10.5 this method was not thread-safe.
  40. static NSString *getaddrinfoLock = @"lock";
  41. #endif
  42.  
  43. enum AsyncUdpSocketFlags
  44. {
  45. kDidBind = 1 << 0, // If set, bind has been called.
  46. kDidConnect = 1 << 1, // If set, connect has been called.
  47. kSock4CanAcceptBytes = 1 << 2, // If set, we know socket4 can accept bytes. If unset, it's unknown.
  48. kSock6CanAcceptBytes = 1 << 3, // If set, we know socket6 can accept bytes. If unset, it's unknown.
  49. kSock4HasBytesAvailable = 1 << 4, // If set, we know socket4 has bytes available. If unset, it's unknown.
  50. kSock6HasBytesAvailable = 1 << 5, // If set, we know socket6 has bytes available. If unset, it's unknown.
  51. kForbidSendReceive = 1 << 6, // If set, no new send or receive operations are allowed to be queued.
  52. kCloseAfterSends = 1 << 7, // If set, close as soon as no more sends are queued.
  53. kCloseAfterReceives = 1 << 8, // If set, close as soon as no more receives are queued.
  54. kDidClose = 1 << 9, // If set, the socket has been closed, and should not be used anymore.
  55. kDequeueSendScheduled = 1 << 10, // If set, a maybeDequeueSend operation is already scheduled.
  56. kDequeueReceiveScheduled = 1 << 11, // If set, a maybeDequeueReceive operation is already scheduled.
  57. kFlipFlop = 1 << 12, // Used to alternate between IPv4 and IPv6 sockets.
  58. };
  59.  
  60. @interface AsyncUdpSocket (Private)
  61.  
  62. // Run Loop
  63. - (void)runLoopAddSource:(CFRunLoopSourceRef)source;
  64. - (void)runLoopRemoveSource:(CFRunLoopSourceRef)source;
  65. - (void)runLoopAddTimer:(NSTimer *)timer;
  66. - (void)runLoopRemoveTimer:(NSTimer *)timer;
  67.  
  68. // Utilities
  69. - (NSString *)addressHost4:(struct sockaddr_in *)pSockaddr4;
  70. - (NSString *)addressHost6:(struct sockaddr_in6 *)pSockaddr6;
  71. - (NSString *)addressHost:(struct sockaddr *)pSockaddr;
  72.  
  73. // Disconnect Implementation
  74. - (void)emptyQueues;
  75. - (void)closeSocket4;
  76. - (void)closeSocket6;
  77. - (void)maybeScheduleClose;
  78.  
  79. // Errors
  80. - (NSError *)getErrnoError;
  81. - (NSError *)getSocketError;
  82. - (NSError *)getIPv4UnavailableError;
  83. - (NSError *)getIPv6UnavailableError;
  84. - (NSError *)getSendTimeoutError;
  85. - (NSError *)getReceiveTimeoutError;
  86.  
  87. // Diagnostics
  88. - (NSString *)connectedHost:(CFSocketRef)socket;
  89. - (UInt16)connectedPort:(CFSocketRef)socket;
  90. - (NSString *)localHost:(CFSocketRef)socket;
  91. - (UInt16)localPort:(CFSocketRef)socket;
  92.  
  93. // Sending
  94. - (BOOL)canAcceptBytes:(CFSocketRef)sockRef;
  95. - (void)scheduleDequeueSend;
  96. - (void)maybeDequeueSend;
  97. - (void)doSend:(CFSocketRef)sockRef;
  98. - (void)completeCurrentSend;
  99. - (void)failCurrentSend:(NSError *)error;
  100. - (void)endCurrentSend;
  101. - (void)doSendTimeout:(NSTimer *)timer;
  102.  
  103. // Receiving
  104. - (BOOL)hasBytesAvailable:(CFSocketRef)sockRef;
  105. - (void)scheduleDequeueReceive;
  106. - (void)maybeDequeueReceive;
  107. - (void)doReceive4;
  108. - (void)doReceive6;
  109. - (void)doReceive:(CFSocketRef)sockRef;
  110. - (BOOL)maybeCompleteCurrentReceive;
  111. - (void)failCurrentReceive:(NSError *)error;
  112. - (void)endCurrentReceive;
  113. - (void)doReceiveTimeout:(NSTimer *)timer;
  114.  
  115. @end
  116.  
  117. static void MyCFSocketCallback(CFSocketRef, CFSocketCallBackType, CFDataRef, const void *, void *);
  118.  
  119. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  120. #pragma mark -
  121. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  122.  
  123. /**
  124. * The AsyncSendPacket encompasses the instructions for a single send/write.
  125. **/
  126. @interface AsyncSendPacket : NSObject
  127. {
  128. @public
  129. NSData *buffer;
  130. NSData *address;
  131. NSTimeInterval timeout;
  132. long tag;
  133. }
  134. - (id)initWithData:(NSData *)d address:(NSData *)a timeout:(NSTimeInterval)t tag:(long)i;
  135. @end
  136.  
  137. @implementation AsyncSendPacket
  138.  
  139. - (id)initWithData:(NSData *)d address:(NSData *)a timeout:(NSTimeInterval)t tag:(long)i
  140. {
  141. if((self = [super init]))
  142. {
  143. buffer = d;
  144. address = a;
  145. timeout = t;
  146. tag = i;
  147. }
  148. return self;
  149. }
  150.  
  151. @end
  152.  
  153. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  154. #pragma mark -
  155. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  156.  
  157. /**
  158. * The AsyncReceivePacket encompasses the instructions for a single receive/read.
  159. **/
  160. @interface AsyncReceivePacket : NSObject
  161. {
  162. @public
  163. NSTimeInterval timeout;
  164. long tag;
  165. NSData *buffer;
  166. NSString *host;
  167. UInt16 port;
  168. }
  169. - (id)initWithTimeout:(NSTimeInterval)t tag:(long)i;
  170. @end
  171.  
  172. @implementation AsyncReceivePacket
  173.  
  174. - (id)initWithTimeout:(NSTimeInterval)t tag:(long)i
  175. {
  176. if((self = [super init]))
  177. {
  178. timeout = t;
  179. tag = i;
  180.  
  181. buffer = nil;
  182. host = nil;
  183. port = 0;
  184. }
  185. return self;
  186. }
  187.  
  188. @end
  189.  
  190. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  191. #pragma mark -
  192. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  193.  
  194. @implementation AsyncUdpSocket
  195.  
  196. - (id)initWithDelegate:(id)delegate userData:(long)userData enableIPv4:(BOOL)enableIPv4 enableIPv6:(BOOL)enableIPv6
  197. {
  198. if((self = [super init]))
  199. {
  200. theFlags = 0;
  201. theDelegate = delegate;
  202. theUserData = userData;
  203. maxReceiveBufferSize = DEFAULT_MAX_RECEIVE_BUFFER_SIZE;
  204.  
  205. theSendQueue = [[NSMutableArray alloc] initWithCapacity:SENDQUEUE_CAPACITY];
  206. theCurrentSend = nil;
  207. theSendTimer = nil;
  208.  
  209. theReceiveQueue = [[NSMutableArray alloc] initWithCapacity:RECEIVEQUEUE_CAPACITY];
  210. theCurrentReceive = nil;
  211. theReceiveTimer = nil;
  212.  
  213. // Socket context
  214. theContext.version = 0;
  215. theContext.info = (__bridge void *)self;
  216. theContext.retain = nil;
  217. theContext.release = nil;
  218. theContext.copyDescription = nil;
  219.  
  220. // Create the sockets
  221. theSocket4 = NULL;
  222. theSocket6 = NULL;
  223.  
  224. if(enableIPv4)
  225. {
  226. theSocket4 = CFSocketCreate(kCFAllocatorDefault,
  227. PF_INET,
  228. SOCK_DGRAM,
  229. IPPROTO_UDP,
  230. kCFSocketReadCallBack | kCFSocketWriteCallBack,
  231. (CFSocketCallBack)&MyCFSocketCallback,
  232. &theContext);
  233. }
  234. if(enableIPv6)
  235. {
  236. theSocket6 = CFSocketCreate(kCFAllocatorDefault,
  237. PF_INET6,
  238. SOCK_DGRAM,
  239. IPPROTO_UDP,
  240. kCFSocketReadCallBack | kCFSocketWriteCallBack,
  241. (CFSocketCallBack)&MyCFSocketCallback,
  242. &theContext);
  243. }
  244.  
  245. // Disable continuous callbacks for read and write.
  246. // If we don't do this, the socket(s) will just sit there firing read callbacks
  247. // at us hundreds of times a second if we don't immediately read the available data.
  248. if(theSocket4)
  249. {
  250. CFSocketSetSocketFlags(theSocket4, kCFSocketCloseOnInvalidate);
  251. }
  252. if(theSocket6)
  253. {
  254. CFSocketSetSocketFlags(theSocket6, kCFSocketCloseOnInvalidate);
  255. }
  256.  
  257. // Get the CFRunLoop to which the socket should be attached.
  258. theRunLoop = CFRunLoopGetCurrent();
  259.  
  260. // Set default run loop modes
  261. theRunLoopModes = [NSArray arrayWithObject:NSDefaultRunLoopMode];
  262.  
  263. // Attach the sockets to the run loop
  264.  
  265. if(theSocket4)
  266. {
  267. theSource4 = CFSocketCreateRunLoopSource(kCFAllocatorDefault, theSocket4, 0);
  268. [self runLoopAddSource:theSource4];
  269. }
  270.  
  271. if(theSocket6)
  272. {
  273. theSource6 = CFSocketCreateRunLoopSource(kCFAllocatorDefault, theSocket6, 0);
  274. [self runLoopAddSource:theSource6];
  275. }
  276.  
  277. cachedLocalPort = 0;
  278. cachedConnectedPort = 0;
  279. }
  280. return self;
  281. }
  282.  
  283. - (id)init
  284. {
  285. return [self initWithDelegate:nil userData:0 enableIPv4:YES enableIPv6:YES];
  286. }
  287.  
  288. - (id)initWithDelegate:(id)delegate
  289. {
  290. return [self initWithDelegate:delegate userData:0 enableIPv4:YES enableIPv6:YES];
  291. }
  292.  
  293. - (id)initWithDelegate:(id)delegate userData:(long)userData
  294. {
  295. return [self initWithDelegate:delegate userData:userData enableIPv4:YES enableIPv6:YES];
  296. }
  297.  
  298. - (id)initIPv4
  299. {
  300. return [self initWithDelegate:nil userData:0 enableIPv4:YES enableIPv6:NO];
  301. }
  302.  
  303. - (id)initIPv6
  304. {
  305. return [self initWithDelegate:nil userData:0 enableIPv4:NO enableIPv6:YES];
  306. }
  307.  
  308. - (void) dealloc
  309. {
  310. [self close];
  311.  
  312. [NSObject cancelPreviousPerformRequestsWithTarget:theDelegate selector:@selector(onUdpSocketDidClose:) object:self];
  313. [NSObject cancelPreviousPerformRequestsWithTarget:self];
  314. }
  315.  
  316. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  317. #pragma mark Accessors
  318. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  319.  
  320. - (id)delegate
  321. {
  322. return theDelegate;
  323. }
  324.  
  325. - (void)setDelegate:(id)delegate
  326. {
  327. theDelegate = delegate;
  328. }
  329.  
  330. - (long)userData
  331. {
  332. return theUserData;
  333. }
  334.  
  335. - (void)setUserData:(long)userData
  336. {
  337. theUserData = userData;
  338. }
  339.  
  340. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  341. #pragma mark Run Loop
  342. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  343.  
  344. - (void)runLoopAddSource:(CFRunLoopSourceRef)source
  345. {
  346. for (NSString *runLoopMode in theRunLoopModes)
  347. {
  348. CFRunLoopAddSource(theRunLoop, source, (__bridge CFStringRef)runLoopMode);
  349. }
  350. }
  351.  
  352. - (void)runLoopRemoveSource:(CFRunLoopSourceRef)source
  353. {
  354. for (NSString *runLoopMode in theRunLoopModes)
  355. {
  356. CFRunLoopRemoveSource(theRunLoop, source, (__bridge CFStringRef)runLoopMode);
  357. }
  358. }
  359.  
  360. - (void)runLoopAddTimer:(NSTimer *)timer
  361. {
  362. for (NSString *runLoopMode in theRunLoopModes)
  363. {
  364. CFRunLoopAddTimer(theRunLoop, (__bridge CFRunLoopTimerRef)timer, (__bridge CFStringRef)runLoopMode);
  365. }
  366. }
  367.  
  368. - (void)runLoopRemoveTimer:(NSTimer *)timer
  369. {
  370. for (NSString *runLoopMode in theRunLoopModes)
  371. {
  372. CFRunLoopRemoveTimer(theRunLoop, (__bridge CFRunLoopTimerRef)timer, (__bridge CFStringRef)runLoopMode);
  373. }
  374. }
  375.  
  376. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  377. #pragma mark Configuration
  378. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  379.  
  380. - (UInt32)maxReceiveBufferSize
  381. {
  382. return maxReceiveBufferSize;
  383. }
  384.  
  385. - (void)setMaxReceiveBufferSize:(UInt32)max
  386. {
  387. maxReceiveBufferSize = max;
  388. }
  389.  
  390. /**
  391. * See the header file for a full explanation of this method.
  392. **/
  393. - (BOOL)moveToRunLoop:(NSRunLoop *)runLoop
  394. {
  395. NSAssert((theRunLoop == NULL) || (theRunLoop == CFRunLoopGetCurrent()),
  396. @"moveToRunLoop must be called from within the current RunLoop!");
  397.  
  398. if(runLoop == nil)
  399. {
  400. return NO;
  401. }
  402. if(theRunLoop == [runLoop getCFRunLoop])
  403. {
  404. return YES;
  405. }
  406.  
  407. [NSObject cancelPreviousPerformRequestsWithTarget:self];
  408. theFlags &= ~kDequeueSendScheduled;
  409. theFlags &= ~kDequeueReceiveScheduled;
  410.  
  411. if(theSource4) [self runLoopRemoveSource:theSource4];
  412. if(theSource6) [self runLoopRemoveSource:theSource6];
  413.  
  414. if(theSendTimer) [self runLoopRemoveTimer:theSendTimer];
  415. if(theReceiveTimer) [self runLoopRemoveTimer:theReceiveTimer];
  416.  
  417. theRunLoop = [runLoop getCFRunLoop];
  418.  
  419. if(theSendTimer) [self runLoopAddTimer:theSendTimer];
  420. if(theReceiveTimer) [self runLoopAddTimer:theReceiveTimer];
  421.  
  422. if(theSource4) [self runLoopAddSource:theSource4];
  423. if(theSource6) [self runLoopAddSource:theSource6];
  424.  
  425. [runLoop performSelector:@selector(maybeDequeueSend) target:self argument:nil order:0 modes:theRunLoopModes];
  426. [runLoop performSelector:@selector(maybeDequeueReceive) target:self argument:nil order:0 modes:theRunLoopModes];
  427. [runLoop performSelector:@selector(maybeScheduleClose) target:self argument:nil order:0 modes:theRunLoopModes];
  428.  
  429. return YES;
  430. }
  431.  
  432. /**
  433. * See the header file for a full explanation of this method.
  434. **/
  435. - (BOOL)setRunLoopModes:(NSArray *)runLoopModes
  436. {
  437. NSAssert((theRunLoop == NULL) || (theRunLoop == CFRunLoopGetCurrent()),
  438. @"setRunLoopModes must be called from within the current RunLoop!");
  439.  
  440. if([runLoopModes count] == 0)
  441. {
  442. return NO;
  443. }
  444. if([theRunLoopModes isEqualToArray:runLoopModes])
  445. {
  446. return YES;
  447. }
  448.  
  449. [NSObject cancelPreviousPerformRequestsWithTarget:self];
  450. theFlags &= ~kDequeueSendScheduled;
  451. theFlags &= ~kDequeueReceiveScheduled;
  452.  
  453. if(theSource4) [self runLoopRemoveSource:theSource4];
  454. if(theSource6) [self runLoopRemoveSource:theSource6];
  455.  
  456. if(theSendTimer) [self runLoopRemoveTimer:theSendTimer];
  457. if(theReceiveTimer) [self runLoopRemoveTimer:theReceiveTimer];
  458.  
  459. theRunLoopModes = [runLoopModes copy];
  460.  
  461. if(theSendTimer) [self runLoopAddTimer:theSendTimer];
  462. if(theReceiveTimer) [self runLoopAddTimer:theReceiveTimer];
  463.  
  464. if(theSource4) [self runLoopAddSource:theSource4];
  465. if(theSource6) [self runLoopAddSource:theSource6];
  466.  
  467. [self performSelector:@selector(maybeDequeueSend) withObject:nil afterDelay:0 inModes:theRunLoopModes];
  468. [self performSelector:@selector(maybeDequeueReceive) withObject:nil afterDelay:0 inModes:theRunLoopModes];
  469. [self performSelector:@selector(maybeScheduleClose) withObject:nil afterDelay:0 inModes:theRunLoopModes];
  470.  
  471. return YES;
  472. }
  473.  
  474. - (NSArray *)runLoopModes
  475. {
  476. return [theRunLoopModes copy];
  477. }
  478.  
  479. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  480. #pragma mark Utilities:
  481. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  482.  
  483. /**
  484. * Attempts to convert the given host/port into and IPv4 and/or IPv6 data structure.
  485. * The data structure is of type sockaddr_in for IPv4 and sockaddr_in6 for IPv6.
  486. *
  487. * Returns zero on success, or one of the error codes listed in gai_strerror if an error occurs (as per getaddrinfo).
  488. **/
  489. - (int)convertForBindHost:(NSString *)host
  490. port:(UInt16)port
  491. intoAddress4:(NSData **)address4
  492. address6:(NSData **)address6
  493. {
  494. if(host == nil || ([host length] == 0))
  495. {
  496. // Use ANY address
  497. struct sockaddr_in nativeAddr;
  498. nativeAddr.sin_len = sizeof(struct sockaddr_in);
  499. nativeAddr.sin_family = AF_INET;
  500. nativeAddr.sin_port = htons(port);
  501. nativeAddr.sin_addr.s_addr = htonl(INADDR_ANY);
  502. memset(&(nativeAddr.sin_zero), 0, sizeof(nativeAddr.sin_zero));
  503.  
  504. struct sockaddr_in6 nativeAddr6;
  505. nativeAddr6.sin6_len = sizeof(struct sockaddr_in6);
  506. nativeAddr6.sin6_family = AF_INET6;
  507. nativeAddr6.sin6_port = htons(port);
  508. nativeAddr6.sin6_flowinfo = 0;
  509. nativeAddr6.sin6_addr = in6addr_any;
  510. nativeAddr6.sin6_scope_id = 0;
  511.  
  512. // Wrap the native address structures for CFSocketSetAddress.
  513. if(address4) *address4 = [NSData dataWithBytes:&nativeAddr length:sizeof(nativeAddr)];
  514. if(address6) *address6 = [NSData dataWithBytes:&nativeAddr6 length:sizeof(nativeAddr6)];
  515.  
  516. return 0;
  517. }
  518. else if([host isEqualToString:@"localhost"] || [host isEqualToString:@"loopback"])
  519. {
  520. // Note: getaddrinfo("localhost",...) fails on 10.5.3
  521.  
  522. // Use LOOPBACK address
  523. struct sockaddr_in nativeAddr;
  524. nativeAddr.sin_len = sizeof(struct sockaddr_in);
  525. nativeAddr.sin_family = AF_INET;
  526. nativeAddr.sin_port = htons(port);
  527. nativeAddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
  528. memset(&(nativeAddr.sin_zero), 0, sizeof(nativeAddr.sin_zero));
  529.  
  530. struct sockaddr_in6 nativeAddr6;
  531. nativeAddr6.sin6_len = sizeof(struct sockaddr_in6);
  532. nativeAddr6.sin6_family = AF_INET6;
  533. nativeAddr6.sin6_port = htons(port);
  534. nativeAddr6.sin6_flowinfo = 0;
  535. nativeAddr6.sin6_addr = in6addr_loopback;
  536. nativeAddr6.sin6_scope_id = 0;
  537.  
  538. // Wrap the native address structures for CFSocketSetAddress.
  539. if(address4) *address4 = [NSData dataWithBytes:&nativeAddr length:sizeof(nativeAddr)];
  540. if(address6) *address6 = [NSData dataWithBytes:&nativeAddr6 length:sizeof(nativeAddr6)];
  541.  
  542. return 0;
  543. }
  544. else
  545. {
  546. NSString *portStr = [NSString stringWithFormat:@"%hu", port];
  547.  
  548. #if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5
  549. @synchronized (getaddrinfoLock)
  550. #endif
  551. {
  552. struct addrinfo hints, *res, *res0;
  553.  
  554. memset(&hints, 0, sizeof(hints));
  555. hints.ai_family = PF_UNSPEC;
  556. hints.ai_socktype = SOCK_DGRAM;
  557. hints.ai_protocol = IPPROTO_UDP;
  558. hints.ai_flags = AI_PASSIVE;
  559.  
  560. int error = getaddrinfo([host UTF8String], [portStr UTF8String], &hints, &res0);
  561.  
  562. if(error) return error;
  563.  
  564. for(res = res0; res; res = res->ai_next)
  565. {
  566. if(address4 && !*address4 && (res->ai_family == AF_INET))
  567. {
  568. // Found IPv4 address
  569. // Wrap the native address structures for CFSocketSetAddress.
  570. if(address4) *address4 = [NSData dataWithBytes:res->ai_addr length:res->ai_addrlen];
  571. }
  572. else if(address6 && !*address6 && (res->ai_family == AF_INET6))
  573. {
  574. // Found IPv6 address
  575. // Wrap the native address structures for CFSocketSetAddress.
  576. if(address6) *address6 = [NSData dataWithBytes:res->ai_addr length:res->ai_addrlen];
  577. }
  578. }
  579. freeaddrinfo(res0);
  580. }
  581.  
  582. return 0;
  583. }
  584. }
  585.  
  586. /**
  587. * Attempts to convert the given host/port into and IPv4 and/or IPv6 data structure.
  588. * The data structure is of type sockaddr_in for IPv4 and sockaddr_in6 for IPv6.
  589. *
  590. * Returns zero on success, or one of the error codes listed in gai_strerror if an error occurs (as per getaddrinfo).
  591. **/
  592. - (int)convertForSendHost:(NSString *)host
  593. port:(UInt16)port
  594. intoAddress4:(NSData **)address4
  595. address6:(NSData **)address6
  596. {
  597. if(host == nil || ([host length] == 0))
  598. {
  599. // We're not binding, so what are we supposed to do with this?
  600. return EAI_NONAME;
  601. }
  602. else if([host isEqualToString:@"localhost"] || [host isEqualToString:@"loopback"])
  603. {
  604. // Note: getaddrinfo("localhost",...) fails on 10.5.3
  605.  
  606. // Use LOOPBACK address
  607. struct sockaddr_in nativeAddr;
  608. nativeAddr.sin_len = sizeof(struct sockaddr_in);
  609. nativeAddr.sin_family = AF_INET;
  610. nativeAddr.sin_port = htons(port);
  611. nativeAddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
  612. memset(&(nativeAddr.sin_zero), 0, sizeof(nativeAddr.sin_zero));
  613.  
  614. struct sockaddr_in6 nativeAddr6;
  615. nativeAddr6.sin6_len = sizeof(struct sockaddr_in6);
  616. nativeAddr6.sin6_family = AF_INET6;
  617. nativeAddr6.sin6_port = htons(port);
  618. nativeAddr6.sin6_flowinfo = 0;
  619. nativeAddr6.sin6_addr = in6addr_loopback;
  620. nativeAddr6.sin6_scope_id = 0;
  621.  
  622. // Wrap the native address structures for CFSocketSetAddress.
  623. if(address4) *address4 = [NSData dataWithBytes:&nativeAddr length:sizeof(nativeAddr)];
  624. if(address6) *address6 = [NSData dataWithBytes:&nativeAddr6 length:sizeof(nativeAddr6)];
  625.  
  626. return 0;
  627. }
  628. else
  629. {
  630. NSString *portStr = [NSString stringWithFormat:@"%hu", port];
  631.  
  632. #if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5
  633. @synchronized (getaddrinfoLock)
  634. #endif
  635. {
  636. struct addrinfo hints, *res, *res0;
  637.  
  638. memset(&hints, 0, sizeof(hints));
  639. hints.ai_family = PF_UNSPEC;
  640. hints.ai_socktype = SOCK_DGRAM;
  641. hints.ai_protocol = IPPROTO_UDP;
  642. // No passive flag on a send or connect
  643.  
  644. int error = getaddrinfo([host UTF8String], [portStr UTF8String], &hints, &res0);
  645.  
  646. if(error) return error;
  647.  
  648. for(res = res0; res; res = res->ai_next)
  649. {
  650. if(address4 && !*address4 && (res->ai_family == AF_INET))
  651. {
  652. // Found IPv4 address
  653. // Wrap the native address structures for CFSocketSetAddress.
  654. if(address4) *address4 = [NSData dataWithBytes:res->ai_addr length:res->ai_addrlen];
  655. }
  656. else if(address6 && !*address6 && (res->ai_family == AF_INET6))
  657. {
  658. // Found IPv6 address
  659. // Wrap the native address structures for CFSocketSetAddress.
  660. if(address6) *address6 = [NSData dataWithBytes:res->ai_addr length:res->ai_addrlen];
  661. }
  662. }
  663. freeaddrinfo(res0);
  664. }
  665.  
  666. return 0;
  667. }
  668. }
  669.  
  670. - (NSString *)addressHost4:(struct sockaddr_in *)pSockaddr4
  671. {
  672. char addrBuf[INET_ADDRSTRLEN];
  673.  
  674. if(inet_ntop(AF_INET, &pSockaddr4->sin_addr, addrBuf, sizeof(addrBuf)) == NULL)
  675. {
  676. [NSException raise:NSInternalInconsistencyException format:@"Cannot convert address to string."];
  677. }
  678.  
  679. return [NSString stringWithCString:addrBuf encoding:NSASCIIStringEncoding];
  680. }
  681.  
  682. - (NSString *)addressHost6:(struct sockaddr_in6 *)pSockaddr6
  683. {
  684. char addrBuf[INET6_ADDRSTRLEN];
  685.  
  686. if(inet_ntop(AF_INET6, &pSockaddr6->sin6_addr, addrBuf, sizeof(addrBuf)) == NULL)
  687. {
  688. [NSException raise:NSInternalInconsistencyException format:@"Cannot convert address to string."];
  689. }
  690.  
  691. return [NSString stringWithCString:addrBuf encoding:NSASCIIStringEncoding];
  692. }
  693.  
  694. - (NSString *)addressHost:(struct sockaddr *)pSockaddr
  695. {
  696. if(pSockaddr->sa_family == AF_INET)
  697. {
  698. return [self addressHost4:(struct sockaddr_in *)pSockaddr];
  699. }
  700. else
  701. {
  702. return [self addressHost6:(struct sockaddr_in6 *)pSockaddr];
  703. }
  704. }
  705.  
  706. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  707. #pragma mark Socket Implementation:
  708. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  709.  
  710. /**
  711. * Binds the underlying socket(s) to the given port.
  712. * The socket(s) will be able to receive data on any interface.
  713. *
  714. * On success, returns YES.
  715. * Otherwise returns NO, and sets errPtr. If you don't care about the error, you can pass nil for errPtr.
  716. **/
  717. - (BOOL)bindToPort:(UInt16)port error:(NSError **)errPtr
  718. {
  719. return [self bindToAddress:nil port:port error:errPtr];
  720. }
  721.  
  722. /**
  723. * Binds the underlying socket(s) to the given address and port.
  724. * The sockets(s) will be able to receive data only on the given interface.
  725. *
  726. * To receive data on any interface, pass nil or "".
  727. * To receive data only on the loopback interface, pass "localhost" or "loopback".
  728. *
  729. * On success, returns YES.
  730. * Otherwise returns NO, and sets errPtr. If you don't care about the error, you can pass nil for errPtr.
  731. **/
  732. - (BOOL)bindToAddress:(NSString *)host port:(UInt16)port error:(NSError **)errPtr
  733. {
  734. if(theFlags & kDidClose)
  735. {
  736. [NSException raise:AsyncUdpSocketException
  737. format:@"The socket is closed."];
  738. }
  739. if(theFlags & kDidBind)
  740. {
  741. [NSException raise:AsyncUdpSocketException
  742. format:@"Cannot bind a socket more than once."];
  743. }
  744. if(theFlags & kDidConnect)
  745. {
  746. [NSException raise:AsyncUdpSocketException
  747. format:@"Cannot bind after connecting. If needed, bind first, then connect."];
  748. }
  749.  
  750. // Convert the given host/port into native address structures for CFSocketSetAddress
  751. NSData *address4 = nil, *address6 = nil;
  752.  
  753. int gai_error = [self convertForBindHost:host port:port intoAddress4:&address4 address6:&address6];
  754. if(gai_error)
  755. {
  756. if(errPtr)
  757. {
  758. NSString *errMsg = [NSString stringWithCString:gai_strerror(gai_error) encoding:NSASCIIStringEncoding];
  759. NSDictionary *info = [NSDictionary dictionaryWithObject:errMsg forKey:NSLocalizedDescriptionKey];
  760.  
  761. *errPtr = [NSError errorWithDomain:@"kCFStreamErrorDomainNetDB" code:gai_error userInfo:info];
  762. }
  763. return NO;
  764. }
  765.  
  766. NSAssert((address4 || address6), @"address4 and address6 are nil");
  767.  
  768. // Set the SO_REUSEADDR flags
  769.  
  770. int reuseOn = 1;
  771. if (theSocket4) setsockopt(CFSocketGetNative(theSocket4), SOL_SOCKET, SO_REUSEADDR, &reuseOn, sizeof(reuseOn));
  772. if (theSocket6) setsockopt(CFSocketGetNative(theSocket6), SOL_SOCKET, SO_REUSEADDR, &reuseOn, sizeof(reuseOn));
  773.  
  774. // Bind the sockets
  775.  
  776. if(address4)
  777. {
  778. if(theSocket4)
  779. {
  780. CFSocketError error = CFSocketSetAddress(theSocket4, (__bridge CFDataRef)address4);
  781. if(error != kCFSocketSuccess)
  782. {
  783. if(errPtr) *errPtr = [self getSocketError];
  784. return NO;
  785. }
  786.  
  787. if(!address6)
  788. {
  789. // Using IPv4 only
  790. [self closeSocket6];
  791. }
  792. }
  793. else if(!address6)
  794. {
  795. if(errPtr) *errPtr = [self getIPv4UnavailableError];
  796. return NO;
  797. }
  798. }
  799.  
  800. if(address6)
  801. {
  802. // Note: The iPhone doesn't currently support IPv6
  803.  
  804. if(theSocket6)
  805. {
  806. CFSocketError error = CFSocketSetAddress(theSocket6, (__bridge CFDataRef)address6);
  807. if(error != kCFSocketSuccess)
  808. {
  809. if(errPtr) *errPtr = [self getSocketError];
  810. return NO;
  811. }
  812.  
  813. if(!address4)
  814. {
  815. // Using IPv6 only
  816. [self closeSocket4];
  817. }
  818. }
  819. else if(!address4)
  820. {
  821. if(errPtr) *errPtr = [self getIPv6UnavailableError];
  822. return NO;
  823. }
  824. }
  825.  
  826. theFlags |= kDidBind;
  827. return YES;
  828. }
  829.  
  830. /**
  831. * Connects the underlying UDP socket to the given host and port.
  832. * If an IPv4 address is resolved, the IPv4 socket is connected, and the IPv6 socket is invalidated and released.
  833. * If an IPv6 address is resolved, the IPv6 socket is connected, and the IPv4 socket is invalidated and released.
  834. *
  835. * On success, returns YES.
  836. * Otherwise returns NO, and sets errPtr. If you don't care about the error, you can pass nil for errPtr.
  837. **/
  838. - (BOOL)connectToHost:(NSString *)host onPort:(UInt16)port error:(NSError **)errPtr
  839. {
  840. if(theFlags & kDidClose)
  841. {
  842. [NSException raise:AsyncUdpSocketException
  843. format:@"The socket is closed."];
  844. }
  845. if(theFlags & kDidConnect)
  846. {
  847. [NSException raise:AsyncUdpSocketException
  848. format:@"Cannot connect a socket more than once."];
  849. }
  850.  
  851. // Convert the given host/port into native address structures for CFSocketSetAddress
  852. NSData *address4 = nil, *address6 = nil;
  853.  
  854. int error = [self convertForSendHost:host port:port intoAddress4:&address4 address6:&address6];
  855. if(error)
  856. {
  857. if(errPtr)
  858. {
  859. NSString *errMsg = [NSString stringWithCString:gai_strerror(error) encoding:NSASCIIStringEncoding];
  860. NSDictionary *info = [NSDictionary dictionaryWithObject:errMsg forKey:NSLocalizedDescriptionKey];
  861.  
  862. *errPtr = [NSError errorWithDomain:@"kCFStreamErrorDomainNetDB" code:error userInfo:info];
  863. }
  864. return NO;
  865. }
  866.  
  867. NSAssert((address4 || address6), @"address4 and address6 are nil");
  868.  
  869. // We only want to connect via a single interface.
  870. // IPv4 is currently preferred, but this may change in the future.
  871.  
  872. CFSocketError sockErr;
  873.  
  874. if (address4)
  875. {
  876. if (theSocket4)
  877. {
  878. sockErr = CFSocketConnectToAddress(theSocket4, (__bridge CFDataRef)address4, (CFTimeInterval)0.0);
  879. if (sockErr != kCFSocketSuccess)
  880. {
  881. if(errPtr) *errPtr = [self getSocketError];
  882. return NO;
  883. }
  884. theFlags |= kDidConnect;
  885.  
  886. // We're connected to an IPv4 address, so no need for the IPv6 socket
  887. [self closeSocket6];
  888.  
  889. return YES;
  890. }
  891. else if(!address6)
  892. {
  893. if(errPtr) *errPtr = [self getIPv4UnavailableError];
  894. return NO;
  895. }
  896. }
  897.  
  898. if (address6)
  899. {
  900. // Note: The iPhone doesn't currently support IPv6
  901.  
  902. if (theSocket6)
  903. {
  904. sockErr = CFSocketConnectToAddress(theSocket6, (__bridge CFDataRef)address6, (CFTimeInterval)0.0);
  905. if (sockErr != kCFSocketSuccess)
  906. {
  907. if(errPtr) *errPtr = [self getSocketError];
  908. return NO;
  909. }
  910. theFlags |= kDidConnect;
  911.  
  912. // We're connected to an IPv6 address, so no need for the IPv4 socket
  913. [self closeSocket4];
  914.  
  915. return YES;
  916. }
  917. else
  918. {
  919. if(errPtr) *errPtr = [self getIPv6UnavailableError];
  920. return NO;
  921. }
  922. }
  923.  
  924. // It shouldn't be possible to get to this point because either address4 or address6 was non-nil.
  925. if(errPtr) *errPtr = nil;
  926. return NO;
  927. }
  928.  
  929. /**
  930. * Connects the underlying UDP socket to the remote address.
  931. * If the address is an IPv4 address, the IPv4 socket is connected, and the IPv6 socket is invalidated and released.
  932. * If the address is an IPv6 address, the IPv6 socket is connected, and the IPv4 socket is invalidated and released.
  933. *
  934. * The address is a native address structure, as may be returned from API's such as Bonjour.
  935. * An address may be created manually by simply wrapping a sockaddr_in or sockaddr_in6 in an NSData object.
  936. *
  937. * On success, returns YES.
  938. * Otherwise returns NO, and sets errPtr. If you don't care about the error, you can pass nil for errPtr.
  939. **/
  940. - (BOOL)connectToAddress:(NSData *)remoteAddr error:(NSError **)errPtr
  941. {
  942. if (theFlags & kDidClose)
  943. {
  944. [NSException raise:AsyncUdpSocketException
  945. format:@"The socket is closed."];
  946. }
  947. if (theFlags & kDidConnect)
  948. {
  949. [NSException raise:AsyncUdpSocketException
  950. format:@"Cannot connect a socket more than once."];
  951. }
  952.  
  953. CFSocketError sockErr;
  954.  
  955. // Is remoteAddr an IPv4 address?
  956. if ([remoteAddr length] == sizeof(struct sockaddr_in))
  957. {
  958. if (theSocket4)
  959. {
  960. sockErr = CFSocketConnectToAddress(theSocket4, (__bridge CFDataRef)remoteAddr, (CFTimeInterval)0.0);
  961. if (sockErr != kCFSocketSuccess)
  962. {
  963. if(errPtr) *errPtr = [self getSocketError];
  964. return NO;
  965. }
  966. theFlags |= kDidConnect;
  967.  
  968. // We're connected to an IPv4 address, so no need for the IPv6 socket
  969. [self closeSocket6];
  970.  
  971. return YES;
  972. }
  973. else
  974. {
  975. if(errPtr) *errPtr = [self getIPv4UnavailableError];
  976. return NO;
  977. }
  978. }
  979.  
  980. // Is remoteAddr an IPv6 address?
  981. if ([remoteAddr length] == sizeof(struct sockaddr_in6))
  982. {
  983. if (theSocket6)
  984. {
  985. sockErr = CFSocketConnectToAddress(theSocket6, (__bridge CFDataRef)remoteAddr, (CFTimeInterval)0.0);
  986. if (sockErr != kCFSocketSuccess)
  987. {
  988. if(errPtr) *errPtr = [self getSocketError];
  989. return NO;
  990. }
  991. theFlags |= kDidConnect;
  992.  
  993. // We're connected to an IPv6 address, so no need for the IPv4 socket
  994. [self closeSocket4];
  995.  
  996. return YES;
  997. }
  998. else
  999. {
  1000. if(errPtr) *errPtr = [self getIPv6UnavailableError];
  1001. return NO;
  1002. }
  1003. }
  1004.  
  1005. // The remoteAddr was invalid
  1006. if(errPtr)
  1007. {
  1008. NSString *errMsg = @"remoteAddr parameter is not a valid address";
  1009. NSDictionary *info = [NSDictionary dictionaryWithObject:errMsg forKey:NSLocalizedDescriptionKey];
  1010.  
  1011. *errPtr = [NSError errorWithDomain:AsyncUdpSocketErrorDomain
  1012. code:AsyncUdpSocketBadParameter
  1013. userInfo:info];
  1014. }
  1015. return NO;
  1016. }
  1017.  
  1018. /**
  1019. * Join multicast group
  1020. *
  1021. * Group should be a multicast IP address (eg. @"239.255.250.250" for IPv4).
  1022. * Address is local interface for IPv4, but currently defaults under IPv6.
  1023. **/
  1024. - (BOOL)joinMulticastGroup:(NSString *)group error:(NSError **)errPtr
  1025. {
  1026. return [self joinMulticastGroup:group withAddress:nil error:errPtr];
  1027. }
  1028.  
  1029. - (BOOL)joinMulticastGroup:(NSString *)group withAddress:(NSString *)address error:(NSError **)errPtr
  1030. {
  1031. if(theFlags & kDidClose)
  1032. {
  1033. [NSException raise:AsyncUdpSocketException
  1034. format:@"The socket is closed."];
  1035. }
  1036. if(!(theFlags & kDidBind))
  1037. {
  1038. [NSException raise:AsyncUdpSocketException
  1039. format:@"Must bind a socket before joining a multicast group."];
  1040. }
  1041. if(theFlags & kDidConnect)
  1042. {
  1043. [NSException raise:AsyncUdpSocketException
  1044. format:@"Cannot join a multicast group if connected."];
  1045. }
  1046.  
  1047. // Get local interface address
  1048. // Convert the given host/port into native address structures for CFSocketSetAddress
  1049. NSData *address4 = nil, *address6 = nil;
  1050.  
  1051. int error = [self convertForBindHost:address port:0 intoAddress4:&address4 address6:&address6];
  1052. if(error)
  1053. {
  1054. if(errPtr)
  1055. {
  1056. NSString *errMsg = [NSString stringWithCString:gai_strerror(error) encoding:NSASCIIStringEncoding];
  1057. NSString *errDsc = [NSString stringWithFormat:@"Invalid parameter 'address': %@", errMsg];
  1058. NSDictionary *info = [NSDictionary dictionaryWithObject:errDsc forKey:NSLocalizedDescriptionKey];
  1059.  
  1060. *errPtr = [NSError errorWithDomain:@"kCFStreamErrorDomainNetDB" code:error userInfo:info];
  1061. }
  1062. return NO;
  1063. }
  1064.  
  1065. NSAssert((address4 || address6), @"address4 and address6 are nil");
  1066.  
  1067. // Get multicast address (group)
  1068. NSData *group4 = nil, *group6 = nil;
  1069.  
  1070. error = [self convertForBindHost:group port:0 intoAddress4:&group4 address6:&group6];
  1071. if(error)
  1072. {
  1073. if(errPtr)
  1074. {
  1075. NSString *errMsg = [NSString stringWithCString:gai_strerror(error) encoding:NSASCIIStringEncoding];
  1076. NSString *errDsc = [NSString stringWithFormat:@"Invalid parameter 'group': %@", errMsg];
  1077. NSDictionary *info = [NSDictionary dictionaryWithObject:errDsc forKey:NSLocalizedDescriptionKey];
  1078.  
  1079. *errPtr = [NSError errorWithDomain:@"kCFStreamErrorDomainNetDB" code:error userInfo:info];
  1080. }
  1081. return NO;
  1082. }
  1083.  
  1084. NSAssert((group4 || group6), @"group4 and group6 are nil");
  1085.  
  1086. if(theSocket4 && group4 && address4)
  1087. {
  1088. const struct sockaddr_in* nativeAddress = [address4 bytes];
  1089. const struct sockaddr_in* nativeGroup = [group4 bytes];
  1090.  
  1091. struct ip_mreq imreq;
  1092. imreq.imr_multiaddr = nativeGroup->sin_addr;
  1093. imreq.imr_interface = nativeAddress->sin_addr;
  1094.  
  1095. // JOIN multicast group on default interface
  1096. error = setsockopt(CFSocketGetNative(theSocket4), IPPROTO_IP, IP_ADD_MEMBERSHIP,
  1097. (const void *)&imreq, sizeof(struct ip_mreq));
  1098. if(error)
  1099. {
  1100. if(errPtr)
  1101. {
  1102. NSString *errMsg = @"Unable to join IPv4 multicast group";
  1103. NSDictionary *info = [NSDictionary dictionaryWithObject:errMsg forKey:NSLocalizedDescriptionKey];
  1104.  
  1105. *errPtr = [NSError errorWithDomain:@"kCFStreamErrorDomainPOSIX" code:error userInfo:info];
  1106. }
  1107. return NO;
  1108. }
  1109.  
  1110. // Using IPv4 only
  1111. [self closeSocket6];
  1112.  
  1113. return YES;
  1114. }
  1115.  
  1116. if(theSocket6 && group6 && address6)
  1117. {
  1118. const struct sockaddr_in6* nativeGroup = [group6 bytes];
  1119.  
  1120. struct ipv6_mreq imreq;
  1121. imreq.ipv6mr_multiaddr = nativeGroup->sin6_addr;
  1122. imreq.ipv6mr_interface = 0;
  1123.  
  1124. // JOIN multicast group on default interface
  1125. error = setsockopt(CFSocketGetNative(theSocket6), IPPROTO_IP, IPV6_JOIN_GROUP,
  1126. (const void *)&imreq, sizeof(struct ipv6_mreq));
  1127. if(error)
  1128. {
  1129. if(errPtr)
  1130. {
  1131. NSString *errMsg = @"Unable to join IPv6 multicast group";
  1132. NSDictionary *info = [NSDictionary dictionaryWithObject:errMsg forKey:NSLocalizedDescriptionKey];
  1133.  
  1134. *errPtr = [NSError errorWithDomain:@"kCFStreamErrorDomainPOSIX" code:error userInfo:info];
  1135. }
  1136. return NO;
  1137. }
  1138.  
  1139. // Using IPv6 only
  1140. [self closeSocket4];
  1141.  
  1142. return YES;
  1143. }
  1144.  
  1145. // The given address and group didn't match the existing socket(s).
  1146. // This means there were no compatible combination of all IPv4 or IPv6 socket, group and address.
  1147. if(errPtr)
  1148. {
  1149. NSString *errMsg = @"Invalid group and/or address, not matching existing socket(s)";
  1150. NSDictionary *info = [NSDictionary dictionaryWithObject:errMsg forKey:NSLocalizedDescriptionKey];
  1151.  
  1152. *errPtr = [NSError errorWithDomain:AsyncUdpSocketErrorDomain
  1153. code:AsyncUdpSocketBadParameter
  1154. userInfo:info];
  1155. }
  1156. return NO;
  1157. }
  1158.  
  1159. /**
  1160. * By default, the underlying socket in the OS will not allow you to send broadcast messages.
  1161. * In order to send broadcast messages, you need to enable this functionality in the socket.
  1162. *
  1163. * A broadcast is a UDP message to addresses like "192.168.255.255" or "255.255.255.255" that is
  1164. * delivered to every host on the network.
  1165. * The reason this is generally disabled by default is to prevent
  1166. * accidental broadcast messages from flooding the network.
  1167. **/
  1168. - (BOOL)enableBroadcast:(BOOL)flag error:(NSError **)errPtr
  1169. {
  1170. if (theSocket4)
  1171. {
  1172. int value = flag ? 1 : 0;
  1173. int error = setsockopt(CFSocketGetNative(theSocket4), SOL_SOCKET, SO_BROADCAST,
  1174. (const void *)&value, sizeof(value));
  1175. if(error)
  1176. {
  1177. if(errPtr)
  1178. {
  1179. NSString *errMsg = @"Unable to enable broadcast message sending";
  1180. NSDictionary *info = [NSDictionary dictionaryWithObject:errMsg forKey:NSLocalizedDescriptionKey];
  1181.  
  1182. *errPtr = [NSError errorWithDomain:@"kCFStreamErrorDomainPOSIX" code:error userInfo:info];
  1183. }
  1184. return NO;
  1185. }
  1186. }
  1187.  
  1188. // IPv6 does not implement broadcast, the ability to send a packet to all hosts on the attached link.
  1189. // The same effect can be achieved by sending a packet to the link-local all hosts multicast group.
  1190.  
  1191. return YES;
  1192. }
  1193.  
  1194. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1195. #pragma mark Disconnect Implementation:
  1196. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1197.  
  1198. - (void)emptyQueues
  1199. {
  1200. if (theCurrentSend) [self endCurrentSend];
  1201. if (theCurrentReceive) [self endCurrentReceive];
  1202.  
  1203. [theSendQueue removeAllObjects];
  1204. [theReceiveQueue removeAllObjects];
  1205.  
  1206. [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(maybeDequeueSend) object:nil];
  1207. [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(maybeDequeueReceive) object:nil];
  1208.  
  1209. theFlags &= ~kDequeueSendScheduled;
  1210. theFlags &= ~kDequeueReceiveScheduled;
  1211. }
  1212.  
  1213. - (void)closeSocket4
  1214. {
  1215. if (theSocket4 != NULL)
  1216. {
  1217. CFSocketInvalidate(theSocket4);
  1218. CFRelease(theSocket4);
  1219. theSocket4 = NULL;
  1220. }
  1221. if (theSource4 != NULL)
  1222. {
  1223. [self runLoopRemoveSource:theSource4];
  1224. CFRelease(theSource4);
  1225. theSource4 = NULL;
  1226. }
  1227. }
  1228.  
  1229. - (void)closeSocket6
  1230. {
  1231. if (theSocket6 != NULL)
  1232. {
  1233. CFSocketInvalidate(theSocket6);
  1234. CFRelease(theSocket6);
  1235. theSocket6 = NULL;
  1236. }
  1237. if (theSource6 != NULL)
  1238. {
  1239. [self runLoopRemoveSource:theSource6];
  1240. CFRelease(theSource6);
  1241. theSource6 = NULL;
  1242. }
  1243. }
  1244.  
  1245. - (void)close
  1246. {
  1247. [self emptyQueues];
  1248. [self closeSocket4];
  1249. [self closeSocket6];
  1250.  
  1251. theRunLoop = NULL;
  1252.  
  1253. // Delay notification to give user freedom to release without returning here and core-dumping.
  1254. if ([theDelegate respondsToSelector:@selector(onUdpSocketDidClose:)])
  1255. {
  1256. [theDelegate performSelector:@selector(onUdpSocketDidClose:)
  1257. withObject:self
  1258. afterDelay:0
  1259. inModes:theRunLoopModes];
  1260. }
  1261.  
  1262. theFlags |= kDidClose;
  1263. }
  1264.  
  1265. - (void)closeAfterSending
  1266. {
  1267. if(theFlags & kDidClose) return;
  1268.  
  1269. theFlags |= (kForbidSendReceive | kCloseAfterSends);
  1270. [self maybeScheduleClose];
  1271. }
  1272.  
  1273. - (void)closeAfterReceiving
  1274. {
  1275. if(theFlags & kDidClose) return;
  1276.  
  1277. theFlags |= (kForbidSendReceive | kCloseAfterReceives);
  1278. [self maybeScheduleClose];
  1279. }
  1280.  
  1281. - (void)closeAfterSendingAndReceiving
  1282. {
  1283. if(theFlags & kDidClose) return;
  1284.  
  1285. theFlags |= (kForbidSendReceive | kCloseAfterSends | kCloseAfterReceives);
  1286. [self maybeScheduleClose];
  1287. }
  1288.  
  1289. - (void)maybeScheduleClose
  1290. {
  1291. BOOL shouldDisconnect = NO;
  1292.  
  1293. if(theFlags & kCloseAfterSends)
  1294. {
  1295. if(([theSendQueue count] == 0) && (theCurrentSend == nil))
  1296. {
  1297. if(theFlags & kCloseAfterReceives)
  1298. {
  1299. if(([theReceiveQueue count] == 0) && (theCurrentReceive == nil))
  1300. {
  1301. shouldDisconnect = YES;
  1302. }
  1303. }
  1304. else
  1305. {
  1306. shouldDisconnect = YES;
  1307. }
  1308. }
  1309. }
  1310. else if(theFlags & kCloseAfterReceives)
  1311. {
  1312. if(([theReceiveQueue count] == 0) && (theCurrentReceive == nil))
  1313. {
  1314. shouldDisconnect = YES;
  1315. }
  1316. }
  1317.  
  1318. if(shouldDisconnect)
  1319. {
  1320. [self performSelector:@selector(close) withObject:nil afterDelay:0 inModes:theRunLoopModes];
  1321. }
  1322. }
  1323.  
  1324. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1325. #pragma mark Errors
  1326. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1327.  
  1328. /**
  1329. * Returns a standard error object for the current errno value.
  1330. * Errno is used for low-level BSD socket errors.
  1331. **/
  1332. - (NSError *)getErrnoError
  1333. {
  1334. NSString *errorMsg = [NSString stringWithUTF8String:strerror(errno)];
  1335. NSDictionary *userInfo = [NSDictionary dictionaryWithObject:errorMsg forKey:NSLocalizedDescriptionKey];
  1336.  
  1337. return [NSError errorWithDomain:NSPOSIXErrorDomain code:errno userInfo:userInfo];
  1338. }
  1339.  
  1340. /**
  1341. * Returns a standard error message for a CFSocket error.
  1342. * Unfortunately, CFSocket offers no feedback on its errors.
  1343. **/
  1344. - (NSError *)getSocketError
  1345. {
  1346. NSString *errMsg = @"General CFSocket error";
  1347. NSDictionary *info = [NSDictionary dictionaryWithObject:errMsg forKey:NSLocalizedDescriptionKey];
  1348.  
  1349. return [NSError errorWithDomain:AsyncUdpSocketErrorDomain code:AsyncUdpSocketCFSocketError userInfo:info];
  1350. }
  1351.  
  1352. - (NSError *)getIPv4UnavailableError
  1353. {
  1354. NSString *errMsg = @"IPv4 is unavailable due to binding/connecting using IPv6 only";
  1355. NSDictionary *info = [NSDictionary dictionaryWithObject:errMsg forKey:NSLocalizedDescriptionKey];
  1356.  
  1357. return [NSError errorWithDomain:AsyncUdpSocketErrorDomain code:AsyncUdpSocketIPv4Unavailable userInfo:info];
  1358. }
  1359.  
  1360. - (NSError *)getIPv6UnavailableError
  1361. {
  1362. NSString *errMsg = @"IPv6 is unavailable due to binding/connecting using IPv4 only or is not supported on this platform";
  1363. NSDictionary *info = [NSDictionary dictionaryWithObject:errMsg forKey:NSLocalizedDescriptionKey];
  1364.  
  1365. return [NSError errorWithDomain:AsyncUdpSocketErrorDomain code:AsyncUdpSocketIPv6Unavailable userInfo:info];
  1366. }
  1367.  
  1368. - (NSError *)getSendTimeoutError
  1369. {
  1370. NSString *errMsg = @"Send operation timed out";
  1371. NSDictionary *info = [NSDictionary dictionaryWithObject:errMsg forKey:NSLocalizedDescriptionKey];
  1372.  
  1373. return [NSError errorWithDomain:AsyncUdpSocketErrorDomain code:AsyncUdpSocketSendTimeoutError userInfo:info];
  1374. }
  1375. - (NSError *)getReceiveTimeoutError
  1376. {
  1377. NSString *errMsg = @"Receive operation timed out";
  1378. NSDictionary *info = [NSDictionary dictionaryWithObject:errMsg forKey:NSLocalizedDescriptionKey];
  1379.  
  1380. return [NSError errorWithDomain:AsyncUdpSocketErrorDomain code:AsyncUdpSocketReceiveTimeoutError userInfo:info];
  1381. }
  1382.  
  1383. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1384. #pragma mark Diagnostics
  1385. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1386.  
  1387. - (NSString *)localHost
  1388. {
  1389. if(cachedLocalHost) return cachedLocalHost;
  1390.  
  1391. if(theSocket4)
  1392. return [self localHost:theSocket4];
  1393. else
  1394. return [self localHost:theSocket6];
  1395. }
  1396.  
  1397. - (UInt16)localPort
  1398. {
  1399. if(cachedLocalPort > 0) return cachedLocalPort;
  1400.  
  1401. if(theSocket4)
  1402. return [self localPort:theSocket4];
  1403. else
  1404. return [self localPort:theSocket6];
  1405. }
  1406.  
  1407. - (NSString *)connectedHost
  1408. {
  1409. if(cachedConnectedHost) return cachedConnectedHost;
  1410.  
  1411. if(theSocket4)
  1412. return [self connectedHost:theSocket4];
  1413. else
  1414. return [self connectedHost:theSocket6];
  1415. }
  1416.  
  1417. - (UInt16)connectedPort
  1418. {
  1419. if(cachedConnectedPort > 0) return cachedConnectedPort;
  1420.  
  1421. if(theSocket4)
  1422. return [self connectedPort:theSocket4];
  1423. else
  1424. return [self connectedPort:theSocket6];
  1425. }
  1426.  
  1427. - (NSString *)localHost:(CFSocketRef)theSocket
  1428. {
  1429. if (theSocket == NULL) return nil;
  1430.  
  1431. // Unfortunately we can't use CFSocketCopyAddress.
  1432. // The CFSocket library caches the address the first time you call CFSocketCopyAddress.
  1433. // So if this is called prior to binding/connecting/sending, it won't be updated again when necessary,
  1434. // and will continue to return the old value of the socket address.
  1435.  
  1436. NSString *result = nil;
  1437.  
  1438. if (theSocket == theSocket4)
  1439. {
  1440. struct sockaddr_in sockaddr4;
  1441. socklen_t sockaddr4len = sizeof(sockaddr4);
  1442.  
  1443. if (getsockname(CFSocketGetNative(theSocket), (struct sockaddr *)&sockaddr4, &sockaddr4len) < 0)
  1444. {
  1445. return nil;
  1446. }
  1447. result = [self addressHost4:&sockaddr4];
  1448. }
  1449. else
  1450. {
  1451. struct sockaddr_in6 sockaddr6;
  1452. socklen_t sockaddr6len = sizeof(sockaddr6);
  1453.  
  1454. if (getsockname(CFSocketGetNative(theSocket), (struct sockaddr *)&sockaddr6, &sockaddr6len) < 0)
  1455. {
  1456. return nil;
  1457. }
  1458. result = [self addressHost6:&sockaddr6];
  1459. }
  1460.  
  1461. if (theFlags & kDidBind)
  1462. {
  1463. cachedLocalHost = [result copy];
  1464. }
  1465.  
  1466. return result;
  1467. }
  1468.  
  1469. - (UInt16)localPort:(CFSocketRef)theSocket
  1470. {
  1471. if (theSocket == NULL) return 0;
  1472.  
  1473. // Unfortunately we can't use CFSocketCopyAddress.
  1474. // The CFSocket library caches the address the first time you call CFSocketCopyAddress.
  1475. // So if this is called prior to binding/connecting/sending, it won't be updated again when necessary,
  1476. // and will continue to return the old value of the socket address.
  1477.  
  1478. UInt16 result = 0;
  1479.  
  1480. if (theSocket == theSocket4)
  1481. {
  1482. struct sockaddr_in sockaddr4;
  1483. socklen_t sockaddr4len = sizeof(sockaddr4);
  1484.  
  1485. if (getsockname(CFSocketGetNative(theSocket), (struct sockaddr *)&sockaddr4, &sockaddr4len) < 0)
  1486. {
  1487. return 0;
  1488. }
  1489. result = ntohs(sockaddr4.sin_port);
  1490. }
  1491. else
  1492. {
  1493. struct sockaddr_in6 sockaddr6;
  1494. socklen_t sockaddr6len = sizeof(sockaddr6);
  1495.  
  1496. if (getsockname(CFSocketGetNative(theSocket), (struct sockaddr *)&sockaddr6, &sockaddr6len) < 0)
  1497. {
  1498. return 0;
  1499. }
  1500. result = ntohs(sockaddr6.sin6_port);
  1501. }
  1502.  
  1503. if (theFlags & kDidBind)
  1504. {
  1505. cachedLocalPort = result;
  1506. }
  1507.  
  1508. return result;
  1509. }
  1510.  
  1511. - (NSString *)connectedHost:(CFSocketRef)theSocket
  1512. {
  1513. if (theSocket == NULL) return nil;
  1514.  
  1515. // Unfortunately we can't use CFSocketCopyPeerAddress.
  1516. // The CFSocket library caches the address the first time you call CFSocketCopyPeerAddress.
  1517. // So if this is called prior to binding/connecting/sending, it may not be updated again when necessary,
  1518. // and will continue to return the old value of the socket peer address.
  1519.  
  1520. NSString *result = nil;
  1521.  
  1522. if (theSocket == theSocket4)
  1523. {
  1524. struct sockaddr_in sockaddr4;
  1525. socklen_t sockaddr4len = sizeof(sockaddr4);
  1526.  
  1527. if (getpeername(CFSocketGetNative(theSocket), (struct sockaddr *)&sockaddr4, &sockaddr4len) < 0)
  1528. {
  1529. return nil;
  1530. }
  1531. result = [self addressHost4:&sockaddr4];
  1532. }
  1533. else
  1534. {
  1535. struct sockaddr_in6 sockaddr6;
  1536. socklen_t sockaddr6len = sizeof(sockaddr6);
  1537.  
  1538. if (getpeername(CFSocketGetNative(theSocket), (struct sockaddr *)&sockaddr6, &sockaddr6len) < 0)
  1539. {
  1540. return nil;
  1541. }
  1542. result = [self addressHost6:&sockaddr6];
  1543. }
  1544.  
  1545. if (theFlags & kDidConnect)
  1546. {
  1547. cachedConnectedHost = [result copy];
  1548. }
  1549.  
  1550. return result;
  1551. }
  1552.  
  1553. - (UInt16)connectedPort:(CFSocketRef)theSocket
  1554. {
  1555. if(theSocket == NULL) return 0;
  1556.  
  1557. // Unfortunately we can't use CFSocketCopyPeerAddress.
  1558. // The CFSocket library caches the address the first time you call CFSocketCopyPeerAddress.
  1559. // So if this is called prior to binding/connecting/sending, it may not be updated again when necessary,
  1560. // and will continue to return the old value of the socket peer address.
  1561.  
  1562. UInt16 result = 0;
  1563.  
  1564. if(theSocket == theSocket4)
  1565. {
  1566. struct sockaddr_in sockaddr4;
  1567. socklen_t sockaddr4len = sizeof(sockaddr4);
  1568.  
  1569. if(getpeername(CFSocketGetNative(theSocket), (struct sockaddr *)&sockaddr4, &sockaddr4len) < 0)
  1570. {
  1571. return 0;
  1572. }
  1573. result = ntohs(sockaddr4.sin_port);
  1574. }
  1575. else
  1576. {
  1577. struct sockaddr_in6 sockaddr6;
  1578. socklen_t sockaddr6len = sizeof(sockaddr6);
  1579.  
  1580. if(getpeername(CFSocketGetNative(theSocket), (struct sockaddr *)&sockaddr6, &sockaddr6len) < 0)
  1581. {
  1582. return 0;
  1583. }
  1584. result = ntohs(sockaddr6.sin6_port);
  1585. }
  1586.  
  1587. if(theFlags & kDidConnect)
  1588. {
  1589. cachedConnectedPort = result;
  1590. }
  1591.  
  1592. return result;
  1593. }
  1594.  
  1595. - (BOOL)isConnected
  1596. {
  1597. return (((theFlags & kDidConnect) != 0) && ((theFlags & kDidClose) == 0));
  1598. }
  1599.  
  1600. - (BOOL)isConnectedToHost:(NSString *)host port:(UInt16)port
  1601. {
  1602. return [[self connectedHost] isEqualToString:host] && ([self connectedPort] == port);
  1603. }
  1604.  
  1605. - (BOOL)isClosed
  1606. {
  1607. return (theFlags & kDidClose) ? YES : NO;
  1608. }
  1609.  
  1610. - (BOOL)isIPv4
  1611. {
  1612. return (theSocket4 != NULL);
  1613. }
  1614.  
  1615. - (BOOL)isIPv6
  1616. {
  1617. return (theSocket6 != NULL);
  1618. }
  1619.  
  1620. - (unsigned int)maximumTransmissionUnit
  1621. {
  1622. CFSocketNativeHandle theNativeSocket;
  1623. if(theSocket4)
  1624. theNativeSocket = CFSocketGetNative(theSocket4);
  1625. else if(theSocket6)
  1626. theNativeSocket = CFSocketGetNative(theSocket6);
  1627. else
  1628. return 0;
  1629.  
  1630. if(theNativeSocket == 0)
  1631. {
  1632. return 0;
  1633. }
  1634.  
  1635. struct ifreq ifr;
  1636. bzero(&ifr, sizeof(ifr));
  1637.  
  1638. if(if_indextoname(theNativeSocket, ifr.ifr_name) == NULL)
  1639. {
  1640. return 0;
  1641. }
  1642.  
  1643. if(ioctl(theNativeSocket, SIOCGIFMTU, &ifr) >= 0)
  1644. {
  1645. return ifr.ifr_mtu;
  1646. }
  1647.  
  1648. return 0;
  1649. }
  1650.  
  1651. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1652. #pragma mark Sending
  1653. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1654.  
  1655. - (BOOL)sendData:(NSData *)data withTimeout:(NSTimeInterval)timeout tag:(long)tag
  1656. {
  1657. if([data length] == 0) return NO;
  1658. if(theFlags & kForbidSendReceive) return NO;
  1659. if(theFlags & kDidClose) return NO;
  1660.  
  1661. // This method is only for connected sockets
  1662. if(![self isConnected]) return NO;
  1663.  
  1664. AsyncSendPacket *packet = [[AsyncSendPacket alloc] initWithData:data address:nil timeout:timeout tag:tag];
  1665.  
  1666. [theSendQueue addObject:packet];
  1667. [self scheduleDequeueSend];
  1668.  
  1669. return YES;
  1670. }
  1671.  
  1672. - (BOOL)sendData:(NSData *)data
  1673. toHost:(NSString *)host
  1674. port:(UInt16)port
  1675. withTimeout:(NSTimeInterval)timeout
  1676. tag:(long)tag
  1677. {
  1678. if([data length] == 0) return NO;
  1679. if(theFlags & kForbidSendReceive) return NO;
  1680. if(theFlags & kDidClose) return NO;
  1681.  
  1682. // This method is only for non-connected sockets
  1683. if([self isConnected]) return NO;
  1684.  
  1685. NSData *address4 = nil, *address6 = nil;
  1686. [self convertForSendHost:host port:port intoAddress4:&address4 address6:&address6];
  1687.  
  1688. AsyncSendPacket *packet = nil;
  1689.  
  1690. if(address4 && theSocket4)
  1691. packet = [[AsyncSendPacket alloc] initWithData:data address:address4 timeout:timeout tag:tag];
  1692. else if(address6 && theSocket6)
  1693. packet = [[AsyncSendPacket alloc] initWithData:data address:address6 timeout:timeout tag:tag];
  1694. else
  1695. return NO;
  1696.  
  1697. [theSendQueue addObject:packet];
  1698. [self scheduleDequeueSend];
  1699.  
  1700. return YES;
  1701. }
  1702.  
  1703. - (BOOL)sendData:(NSData *)data toAddress:(NSData *)remoteAddr withTimeout:(NSTimeInterval)timeout tag:(long)tag
  1704. {
  1705. if([data length] == 0) return NO;
  1706. if(theFlags & kForbidSendReceive) return NO;
  1707. if(theFlags & kDidClose) return NO;
  1708.  
  1709. // This method is only for non-connected sockets
  1710. if([self isConnected]) return NO;
  1711.  
  1712. if([remoteAddr length] == sizeof(struct sockaddr_in) && !theSocket4)
  1713. return NO;
  1714.  
  1715. if([remoteAddr length] == sizeof(struct sockaddr_in6) && !theSocket6)
  1716. return NO;
  1717.  
  1718. AsyncSendPacket *packet = [[AsyncSendPacket alloc] initWithData:data address:remoteAddr timeout:timeout tag:tag];
  1719.  
  1720. [theSendQueue addObject:packet];
  1721. [self scheduleDequeueSend];
  1722.  
  1723. return YES;
  1724. }
  1725.  
  1726. - (BOOL)canAcceptBytes:(CFSocketRef)sockRef
  1727. {
  1728. if(sockRef == theSocket4)
  1729. {
  1730. if(theFlags & kSock4CanAcceptBytes) return YES;
  1731. }
  1732. else
  1733. {
  1734. if(theFlags & kSock6CanAcceptBytes) return YES;
  1735. }
  1736.  
  1737. CFSocketNativeHandle theNativeSocket = CFSocketGetNative(sockRef);
  1738.  
  1739. if(theNativeSocket == 0)
  1740. {
  1741. NSLog(@"Error - Could not get CFSocketNativeHandle from CFSocketRef");
  1742. return NO;
  1743. }
  1744.  
  1745. fd_set fds;
  1746. FD_ZERO(&fds);
  1747. FD_SET(theNativeSocket, &fds);
  1748.  
  1749. struct timeval timeout;
  1750. timeout.tv_sec = 0;
  1751. timeout.tv_usec = 0;
  1752.  
  1753. return select(FD_SETSIZE, NULL, &fds, NULL, &timeout) > 0;
  1754. }
  1755.  
  1756. - (CFSocketRef)socketForPacket:(AsyncSendPacket *)packet
  1757. {
  1758. if(!theSocket4)
  1759. return theSocket6;
  1760. if(!theSocket6)
  1761. return theSocket4;
  1762.  
  1763. return ([packet->address length] == sizeof(struct sockaddr_in)) ? theSocket4 : theSocket6;
  1764. }
  1765.  
  1766. /**
  1767. * Puts a maybeDequeueSend on the run loop.
  1768. **/
  1769. - (void)scheduleDequeueSend
  1770. {
  1771. if((theFlags & kDequeueSendScheduled) == 0)
  1772. {
  1773. theFlags |= kDequeueSendScheduled;
  1774. [self performSelector:@selector(maybeDequeueSend) withObject:nil afterDelay:0 inModes:theRunLoopModes];
  1775. }
  1776. }
  1777.  
  1778. /**
  1779. * This method starts a new send, if needed.
  1780. * It is called when a user requests a send.
  1781. **/
  1782. - (void)maybeDequeueSend
  1783. {
  1784. // Unset the flag indicating a call to this method is scheduled
  1785. theFlags &= ~kDequeueSendScheduled;
  1786.  
  1787. if(theCurrentSend == nil)
  1788. {
  1789. if([theSendQueue count] > 0)
  1790. {
  1791. // Dequeue next send packet
  1792. theCurrentSend = [theSendQueue objectAtIndex:0];
  1793. [theSendQueue removeObjectAtIndex:0];
  1794.  
  1795. // Start time-out timer.
  1796. if(theCurrentSend->timeout >= 0.0)
  1797. {
  1798. theSendTimer = [NSTimer timerWithTimeInterval:theCurrentSend->timeout
  1799. target:self
  1800. selector:@selector(doSendTimeout:)
  1801. userInfo:nil
  1802. repeats:NO];
  1803.  
  1804. [self runLoopAddTimer:theSendTimer];
  1805. }
  1806.  
  1807. // Immediately send, if possible.
  1808. [self doSend:[self socketForPacket:theCurrentSend]];
  1809. }
  1810. else if(theFlags & kCloseAfterSends)
  1811. {
  1812. if(theFlags & kCloseAfterReceives)
  1813. {
  1814. if(([theReceiveQueue count] == 0) && (theCurrentReceive == nil))
  1815. {
  1816. [self close];
  1817. }
  1818. }
  1819. else
  1820. {
  1821. [self close];
  1822. }
  1823. }
  1824. }
  1825. }
  1826.  
  1827. /**
  1828. * This method is called when a new read is taken from the read queue or when new data becomes available on the stream.
  1829. **/
  1830. - (void)doSend:(CFSocketRef)theSocket
  1831. {
  1832. if(theCurrentSend != nil)
  1833. {
  1834. if(theSocket != [self socketForPacket:theCurrentSend])
  1835. {
  1836. // Current send is for the other socket
  1837. return;
  1838. }
  1839.  
  1840. if([self canAcceptBytes:theSocket])
  1841. {
  1842. ssize_t result;
  1843. CFSocketNativeHandle theNativeSocket = CFSocketGetNative(theSocket);
  1844.  
  1845. const void *buf = [theCurrentSend->buffer bytes];
  1846. NSUInteger bufSize = [theCurrentSend->buffer length];
  1847.  
  1848. if([self isConnected])
  1849. {
  1850. result = send(theNativeSocket, buf, (size_t)bufSize, 0);
  1851. }
  1852. else
  1853. {
  1854. const void *dst = [theCurrentSend->address bytes];
  1855. NSUInteger dstSize = [theCurrentSend->address length];
  1856.  
  1857. result = sendto(theNativeSocket, buf, (size_t)bufSize, 0, dst, (socklen_t)dstSize);
  1858. }
  1859.  
  1860. if(theSocket == theSocket4)
  1861. theFlags &= ~kSock4CanAcceptBytes;
  1862. else
  1863. theFlags &= ~kSock6CanAcceptBytes;
  1864.  
  1865. if(result < 0)
  1866. {
  1867. [self failCurrentSend:[self getErrnoError]];
  1868. }
  1869. else
  1870. {
  1871. // If it wasn't bound before, it's bound now
  1872. theFlags |= kDidBind;
  1873.  
  1874. [self completeCurrentSend];
  1875. }
  1876.  
  1877. [self scheduleDequeueSend];
  1878. }
  1879. else
  1880. {
  1881. // Request notification when the socket is ready to send more data
  1882. CFSocketEnableCallBacks(theSocket, kCFSocketReadCallBack | kCFSocketWriteCallBack);
  1883. }
  1884. }
  1885. }
  1886.  
  1887. - (void)completeCurrentSend
  1888. {
  1889. NSAssert (theCurrentSend, @"Trying to complete current send when there is no current send.");
  1890.  
  1891. if ([theDelegate respondsToSelector:@selector(onUdpSocket:didSendDataWithTag:)])
  1892. {
  1893. [theDelegate onUdpSocket:self didSendDataWithTag:theCurrentSend->tag];
  1894. }
  1895.  
  1896. if (theCurrentSend != nil) [self endCurrentSend]; // Caller may have disconnected.
  1897. }
  1898.  
  1899. - (void)failCurrentSend:(NSError *)error
  1900. {
  1901. NSAssert (theCurrentSend, @"Trying to fail current send when there is no current send.");
  1902.  
  1903. if ([theDelegate respondsToSelector:@selector(onUdpSocket:didNotSendDataWithTag:dueToError:)])
  1904. {
  1905. [theDelegate onUdpSocket:self didNotSendDataWithTag:theCurrentSend->tag dueToError:error];
  1906. }
  1907.  
  1908. if (theCurrentSend != nil) [self endCurrentSend]; // Caller may have disconnected.
  1909. }
  1910.  
  1911. /**
  1912. * Ends the current send, and all associated variables such as the send timer.
  1913. **/
  1914. - (void)endCurrentSend
  1915. {
  1916. NSAssert (theCurrentSend, @"Trying to end current send when there is no current send.");
  1917.  
  1918. [theSendTimer invalidate];
  1919. theSendTimer = nil;
  1920.  
  1921. theCurrentSend = nil;
  1922. }
  1923.  
  1924. - (void)doSendTimeout:(NSTimer *)timer
  1925. {
  1926. if (timer != theSendTimer) return; // Old timer. Ignore it.
  1927. if (theCurrentSend != nil)
  1928. {
  1929. [self failCurrentSend:[self getSendTimeoutError]];
  1930. [self scheduleDequeueSend];
  1931. }
  1932. }
  1933.  
  1934. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1935. #pragma mark Receiving
  1936. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1937.  
  1938. - (void)receiveWithTimeout:(NSTimeInterval)timeout tag:(long)tag
  1939. {
  1940. if(theFlags & kForbidSendReceive) return;
  1941. if(theFlags & kDidClose) return;
  1942.  
  1943. AsyncReceivePacket *packet = [[AsyncReceivePacket alloc] initWithTimeout:timeout tag:tag];
  1944.  
  1945. [theReceiveQueue addObject:packet];
  1946. [self scheduleDequeueReceive];
  1947. }
  1948.  
  1949. - (BOOL)hasBytesAvailable:(CFSocketRef)sockRef
  1950. {
  1951. if(sockRef == theSocket4)
  1952. {
  1953. if(theFlags & kSock4HasBytesAvailable) return YES;
  1954. }
  1955. else
  1956. {
  1957. if(theFlags & kSock6HasBytesAvailable) return YES;
  1958. }
  1959.  
  1960. CFSocketNativeHandle theNativeSocket = CFSocketGetNative(sockRef);
  1961.  
  1962. if(theNativeSocket == 0)
  1963. {
  1964. NSLog(@"Error - Could not get CFSocketNativeHandle from CFSocketRef");
  1965. return NO;
  1966. }
  1967.  
  1968. fd_set fds;
  1969. FD_ZERO(&fds);
  1970. FD_SET(theNativeSocket, &fds);
  1971.  
  1972. struct timeval timeout;
  1973. timeout.tv_sec = 0;
  1974. timeout.tv_usec = 0;
  1975.  
  1976. return select(FD_SETSIZE, &fds, NULL, NULL, &timeout) > 0;
  1977. }
  1978.  
  1979. /**
  1980. * Puts a maybeDequeueReceive on the run loop.
  1981. **/
  1982. - (void)scheduleDequeueReceive
  1983. {
  1984. if((theFlags & kDequeueReceiveScheduled) == 0)
  1985. {
  1986. theFlags |= kDequeueReceiveScheduled;
  1987. [self performSelector:@selector(maybeDequeueReceive) withObject:nil afterDelay:0 inModes:theRunLoopModes];
  1988. }
  1989. }
  1990.  
  1991. /**
  1992. * Starts a new receive operation if needed
  1993. **/
  1994. - (void)maybeDequeueReceive
  1995. {
  1996. // Unset the flag indicating a call to this method is scheduled
  1997. theFlags &= ~kDequeueReceiveScheduled;
  1998.  
  1999. if (theCurrentReceive == nil)
  2000. {
  2001. if ([theReceiveQueue count] > 0)
  2002. {
  2003. // Dequeue next receive packet
  2004. theCurrentReceive = [theReceiveQueue objectAtIndex:0];
  2005. [theReceiveQueue removeObjectAtIndex:0];
  2006.  
  2007. // Start time-out timer.
  2008. if (theCurrentReceive->timeout >= 0.0)
  2009. {
  2010. theReceiveTimer = [NSTimer timerWithTimeInterval:theCurrentReceive->timeout
  2011. target:self
  2012. selector:@selector(doReceiveTimeout:)
  2013. userInfo:nil
  2014. repeats:NO];
  2015.  
  2016. [self runLoopAddTimer:theReceiveTimer];
  2017. }
  2018.  
  2019. // Immediately receive, if possible
  2020. // We always check both sockets so we don't ever starve one of them.
  2021. // We also check them in alternating orders to prevent starvation if both of them
  2022. // have a continuous flow of incoming data.
  2023. if(theFlags & kFlipFlop)
  2024. {
  2025. [self doReceive4];
  2026. [self doReceive6];
  2027. }
  2028. else
  2029. {
  2030. [self doReceive6];
  2031. [self doReceive4];
  2032. }
  2033.  
  2034. theFlags ^= kFlipFlop;
  2035. }
  2036. else if(theFlags & kCloseAfterReceives)
  2037. {
  2038. if(theFlags & kCloseAfterSends)
  2039. {
  2040. if(([theSendQueue count] == 0) && (theCurrentSend == nil))
  2041. {
  2042. [self close];
  2043. }
  2044. }
  2045. else
  2046. {
  2047. [self close];
  2048. }
  2049. }
  2050. }
  2051. }
  2052.  
  2053. - (void)doReceive4
  2054. {
  2055. if(theSocket4) [self doReceive:theSocket4];
  2056. }
  2057.  
  2058. - (void)doReceive6
  2059. {
  2060. if(theSocket6) [self doReceive:theSocket6];
  2061. }
  2062.  
  2063. - (void)doReceive:(CFSocketRef)theSocket
  2064. {
  2065. if (theCurrentReceive != nil)
  2066. {
  2067. BOOL appIgnoredReceivedData;
  2068. BOOL userIgnoredReceivedData;
  2069.  
  2070. do
  2071. {
  2072. // Set or reset ignored variables.
  2073. // If the app or user ignores the received data, we'll continue this do-while loop.
  2074. appIgnoredReceivedData = NO;
  2075. userIgnoredReceivedData = NO;
  2076.  
  2077. if([self hasBytesAvailable:theSocket])
  2078. {
  2079. ssize_t result;
  2080. CFSocketNativeHandle theNativeSocket = CFSocketGetNative(theSocket);
  2081.  
  2082. // Allocate buffer for recvfrom operation.
  2083. // If the operation is successful, we'll realloc the buffer to the appropriate size,
  2084. // and create an NSData wrapper around it without needing to copy any bytes around.
  2085. void *buf = malloc(maxReceiveBufferSize);
  2086. size_t bufSize = maxReceiveBufferSize;
  2087.  
  2088. if(theSocket == theSocket4)
  2089. {
  2090. struct sockaddr_in sockaddr4;
  2091. socklen_t sockaddr4len = sizeof(sockaddr4);
  2092.  
  2093. result = recvfrom(theNativeSocket, buf, bufSize, 0, (struct sockaddr *)&sockaddr4, &sockaddr4len);
  2094.  
  2095. if(result >= 0)
  2096. {
  2097. NSString *host = [self addressHost4:&sockaddr4];
  2098. UInt16 port = ntohs(sockaddr4.sin_port);
  2099.  
  2100. if([self isConnected] && ![self isConnectedToHost:host port:port])
  2101. {
  2102. // The user connected to an address, and the received data doesn't match the address.
  2103. // This may happen if the data is received by the kernel prior to the connect call.
  2104. appIgnoredReceivedData = YES;
  2105. }
  2106. else
  2107. {
  2108. if(result != bufSize)
  2109. {
  2110. buf = realloc(buf, result);
  2111. }
  2112. theCurrentReceive->buffer = [[NSData alloc] initWithBytesNoCopy:buf
  2113. length:result
  2114. freeWhenDone:YES];
  2115. theCurrentReceive->host = host;
  2116. theCurrentReceive->port = port;
  2117. }
  2118. }
  2119.  
  2120. theFlags &= ~kSock4HasBytesAvailable;
  2121. }
  2122. else
  2123. {
  2124. struct sockaddr_in6 sockaddr6;
  2125. socklen_t sockaddr6len = sizeof(sockaddr6);
  2126.  
  2127. result = recvfrom(theNativeSocket, buf, bufSize, 0, (struct sockaddr *)&sockaddr6, &sockaddr6len);
  2128.  
  2129. if(result >= 0)
  2130. {
  2131. NSString *host = [self addressHost6:&sockaddr6];
  2132. UInt16 port = ntohs(sockaddr6.sin6_port);
  2133.  
  2134. if([self isConnected] && ![self isConnectedToHost:host port:port])
  2135. {
  2136. // The user connected to an address, and the received data doesn't match the address.
  2137. // This may happen if the data is received by the kernel prior to the connect call.
  2138. appIgnoredReceivedData = YES;
  2139. }
  2140. else
  2141. {
  2142. if(result != bufSize)
  2143. {
  2144. buf = realloc(buf, result);
  2145. }
  2146. theCurrentReceive->buffer = [[NSData alloc] initWithBytesNoCopy:buf
  2147. length:result
  2148. freeWhenDone:YES];
  2149. theCurrentReceive->host = host;
  2150. theCurrentReceive->port = port;
  2151. }
  2152. }
  2153.  
  2154. theFlags &= ~kSock6HasBytesAvailable;
  2155. }
  2156.  
  2157. // Check to see if we need to free our alloc'd buffer
  2158. // If the buffer is non-nil, this means it has taken ownership of the buffer
  2159. if(theCurrentReceive->buffer == nil)
  2160. {
  2161. free(buf);
  2162. }
  2163.  
  2164. if(result < 0)
  2165. {
  2166. [self failCurrentReceive:[self getErrnoError]];
  2167. [self scheduleDequeueReceive];
  2168. }
  2169. else if(!appIgnoredReceivedData)
  2170. {
  2171. BOOL finished = [self maybeCompleteCurrentReceive];
  2172.  
  2173. if(finished)
  2174. {
  2175. [self scheduleDequeueReceive];
  2176. }
  2177. else
  2178. {
  2179. theCurrentReceive->buffer = nil;
  2180. theCurrentReceive->host = nil;
  2181.  
  2182. userIgnoredReceivedData = YES;
  2183. }
  2184. }
  2185. }
  2186. else
  2187. {
  2188. // Request notification when the socket is ready to receive more data
  2189. CFSocketEnableCallBacks(theSocket, kCFSocketReadCallBack | kCFSocketWriteCallBack);
  2190. }
  2191.  
  2192. } while(appIgnoredReceivedData || userIgnoredReceivedData);
  2193. }
  2194. }
  2195.  
  2196. - (BOOL)maybeCompleteCurrentReceive
  2197. {
  2198. NSAssert (theCurrentReceive, @"Trying to complete current receive when there is no current receive.");
  2199.  
  2200. BOOL finished = YES;
  2201.  
  2202. if ([theDelegate respondsToSelector:@selector(onUdpSocket:didReceiveData:withTag:fromHost:port:)])
  2203. {
  2204. finished = [theDelegate onUdpSocket:self
  2205. didReceiveData:theCurrentReceive->buffer
  2206. withTag:theCurrentReceive->tag
  2207. fromHost:theCurrentReceive->host
  2208. port:theCurrentReceive->port];
  2209. }
  2210.  
  2211. if (finished)
  2212. {
  2213. if (theCurrentReceive != nil) [self endCurrentReceive]; // Caller may have disconnected.
  2214. }
  2215. return finished;
  2216. }
  2217.  
  2218. - (void)failCurrentReceive:(NSError *)error
  2219. {
  2220. NSAssert (theCurrentReceive, @"Trying to fail current receive when there is no current receive.");
  2221.  
  2222. if ([theDelegate respondsToSelector:@selector(onUdpSocket:didNotReceiveDataWithTag:dueToError:)])
  2223. {
  2224. [theDelegate onUdpSocket:self didNotReceiveDataWithTag:theCurrentReceive->tag dueToError:error];
  2225. }
  2226.  
  2227. if (theCurrentReceive != nil) [self endCurrentReceive]; // Caller may have disconnected.
  2228. }
  2229.  
  2230. - (void)endCurrentReceive
  2231. {
  2232. NSAssert (theCurrentReceive, @"Trying to end current receive when there is no current receive.");
  2233.  
  2234. [theReceiveTimer invalidate];
  2235. theReceiveTimer = nil;
  2236.  
  2237. theCurrentReceive = nil;
  2238. }
  2239.  
  2240. - (void)doReceiveTimeout:(NSTimer *)timer
  2241. {
  2242. if (timer != theReceiveTimer) return; // Old timer. Ignore it.
  2243. if (theCurrentReceive != nil)
  2244. {
  2245. [self failCurrentReceive:[self getReceiveTimeoutError]];
  2246. [self scheduleDequeueReceive];
  2247. }
  2248. }
  2249.  
  2250. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2251. #pragma mark CF Callbacks
  2252. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2253.  
  2254. - (void)doCFSocketCallback:(CFSocketCallBackType)type
  2255. forSocket:(CFSocketRef)sock
  2256. withAddress:(NSData *)address
  2257. withData:(const void *)pData
  2258. {
  2259. NSParameterAssert((sock == theSocket4) || (sock == theSocket6));
  2260.  
  2261. switch (type)
  2262. {
  2263. case kCFSocketReadCallBack:
  2264. if(sock == theSocket4)
  2265. theFlags |= kSock4HasBytesAvailable;
  2266. else
  2267. theFlags |= kSock6HasBytesAvailable;
  2268. [self doReceive:sock];
  2269. break;
  2270. case kCFSocketWriteCallBack:
  2271. if(sock == theSocket4)
  2272. theFlags |= kSock4CanAcceptBytes;
  2273. else
  2274. theFlags |= kSock6CanAcceptBytes;
  2275. [self doSend:sock];
  2276. break;
  2277. default:
  2278. NSLog (@"AsyncUdpSocket %p received unexpected CFSocketCallBackType %lu.", self, (unsigned long)type);
  2279. break;
  2280. }
  2281. }
  2282.  
  2283. /**
  2284. * This is the callback we setup for CFSocket.
  2285. * This method does nothing but forward the call to it's Objective-C counterpart
  2286. **/
  2287. static void MyCFSocketCallback(CFSocketRef sref, CFSocketCallBackType type, CFDataRef address, const void *pData, void *pInfo)
  2288. {
  2289. @autoreleasepool {
  2290.  
  2291. AsyncUdpSocket *theSocket = (__bridge AsyncUdpSocket *)pInfo;
  2292. [theSocket doCFSocketCallback:type forSocket:sref withAddress:(__bridge NSData *)address withData:pData];
  2293.  
  2294. }
  2295. }
  2296.  
  2297. @end
Add Comment
Please, Sign In to add comment