Subversion Repositories Mobile Apps.GyroMouse

Rev

Details | Last modification | View Log | RSS feed

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