Subversion Repositories Mobile Apps.GyroMouse

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 pmbaty 1
//
2
//  GCDAsyncSocket.m
3
//  
4
//  This class is in the public domain.
5
//  Originally created by Robbie Hanson in Q4 2010.
6
//  Updated and maintained by Deusty LLC and the Apple development community.
7
//
8
//  https://github.com/robbiehanson/CocoaAsyncSocket
9
//
10
 
11
#import "GCDAsyncSocket.h"
12
 
13
#if TARGET_OS_IPHONE
14
#import <CFNetwork/CFNetwork.h>
15
#endif
16
 
17
#import <TargetConditionals.h>
18
#import <arpa/inet.h>
19
#import <fcntl.h>
20
#import <ifaddrs.h>
21
#import <netdb.h>
22
#import <netinet/in.h>
23
#import <net/if.h>
24
#import <sys/socket.h>
25
#import <sys/types.h>
26
#import <sys/ioctl.h>
27
#import <sys/poll.h>
28
#import <sys/uio.h>
29
#import <sys/un.h>
30
#import <unistd.h>
31
 
32
#if ! __has_feature(objc_arc)
33
#warning This file must be compiled with ARC. Use -fobjc-arc flag (or convert project to ARC).
34
// For more information see: https://github.com/robbiehanson/CocoaAsyncSocket/wiki/ARC
35
#endif
36
 
37
 
38
#ifndef GCDAsyncSocketLoggingEnabled
39
#define GCDAsyncSocketLoggingEnabled 0
40
#endif
41
 
42
#if GCDAsyncSocketLoggingEnabled
43
 
44
// Logging Enabled - See log level below
45
 
46
// Logging uses the CocoaLumberjack framework (which is also GCD based).
47
// https://github.com/robbiehanson/CocoaLumberjack
48
//
49
// It allows us to do a lot of logging without significantly slowing down the code.
50
#import "DDLog.h"
51
 
52
#define LogAsync   YES
53
#define LogContext GCDAsyncSocketLoggingContext
54
 
55
#define LogObjc(flg, frmt, ...) LOG_OBJC_MAYBE(LogAsync, logLevel, flg, LogContext, frmt, ##__VA_ARGS__)
56
#define LogC(flg, frmt, ...)    LOG_C_MAYBE(LogAsync, logLevel, flg, LogContext, frmt, ##__VA_ARGS__)
57
 
58
#define LogError(frmt, ...)     LogObjc(LOG_FLAG_ERROR,   (@"%@: " frmt), THIS_FILE, ##__VA_ARGS__)
59
#define LogWarn(frmt, ...)      LogObjc(LOG_FLAG_WARN,    (@"%@: " frmt), THIS_FILE, ##__VA_ARGS__)
60
#define LogInfo(frmt, ...)      LogObjc(LOG_FLAG_INFO,    (@"%@: " frmt), THIS_FILE, ##__VA_ARGS__)
61
#define LogVerbose(frmt, ...)   LogObjc(LOG_FLAG_VERBOSE, (@"%@: " frmt), THIS_FILE, ##__VA_ARGS__)
62
 
63
#define LogCError(frmt, ...)    LogC(LOG_FLAG_ERROR,   (@"%@: " frmt), THIS_FILE, ##__VA_ARGS__)
64
#define LogCWarn(frmt, ...)     LogC(LOG_FLAG_WARN,    (@"%@: " frmt), THIS_FILE, ##__VA_ARGS__)
65
#define LogCInfo(frmt, ...)     LogC(LOG_FLAG_INFO,    (@"%@: " frmt), THIS_FILE, ##__VA_ARGS__)
66
#define LogCVerbose(frmt, ...)  LogC(LOG_FLAG_VERBOSE, (@"%@: " frmt), THIS_FILE, ##__VA_ARGS__)
67
 
68
#define LogTrace()              LogObjc(LOG_FLAG_VERBOSE, @"%@: %@", THIS_FILE, THIS_METHOD)
69
#define LogCTrace()             LogC(LOG_FLAG_VERBOSE, @"%@: %s", THIS_FILE, __FUNCTION__)
70
 
71
#ifndef GCDAsyncSocketLogLevel
72
#define GCDAsyncSocketLogLevel LOG_LEVEL_VERBOSE
73
#endif
74
 
75
// Log levels : off, error, warn, info, verbose
76
static const int logLevel = GCDAsyncSocketLogLevel;
77
 
78
#else
79
 
80
// Logging Disabled
81
 
82
#define LogError(frmt, ...)     {}
83
#define LogWarn(frmt, ...)      {}
84
#define LogInfo(frmt, ...)      {}
85
#define LogVerbose(frmt, ...)   {}
86
 
87
#define LogCError(frmt, ...)    {}
88
#define LogCWarn(frmt, ...)     {}
89
#define LogCInfo(frmt, ...)     {}
90
#define LogCVerbose(frmt, ...)  {}
91
 
92
#define LogTrace()              {}
93
#define LogCTrace(frmt, ...)    {}
94
 
95
#endif
96
 
97
/**
98
 * Seeing a return statements within an inner block
99
 * can sometimes be mistaken for a return point of the enclosing method.
100
 * This makes inline blocks a bit easier to read.
101
**/
102
#define return_from_block  return
103
 
104
/**
105
 * A socket file descriptor is really just an integer.
106
 * It represents the index of the socket within the kernel.
107
 * This makes invalid file descriptor comparisons easier to read.
108
**/
109
#define SOCKET_NULL -1
110
 
111
 
112
NSString *const GCDAsyncSocketException = @"GCDAsyncSocketException";
113
NSString *const GCDAsyncSocketErrorDomain = @"GCDAsyncSocketErrorDomain";
114
 
115
NSString *const GCDAsyncSocketQueueName = @"GCDAsyncSocket";
116
NSString *const GCDAsyncSocketThreadName = @"GCDAsyncSocket-CFStream";
117
 
118
NSString *const GCDAsyncSocketManuallyEvaluateTrust = @"GCDAsyncSocketManuallyEvaluateTrust";
119
#if TARGET_OS_IPHONE
120
NSString *const GCDAsyncSocketUseCFStreamForTLS = @"GCDAsyncSocketUseCFStreamForTLS";
121
#endif
122
NSString *const GCDAsyncSocketSSLPeerID = @"GCDAsyncSocketSSLPeerID";
123
NSString *const GCDAsyncSocketSSLProtocolVersionMin = @"GCDAsyncSocketSSLProtocolVersionMin";
124
NSString *const GCDAsyncSocketSSLProtocolVersionMax = @"GCDAsyncSocketSSLProtocolVersionMax";
125
NSString *const GCDAsyncSocketSSLSessionOptionFalseStart = @"GCDAsyncSocketSSLSessionOptionFalseStart";
126
NSString *const GCDAsyncSocketSSLSessionOptionSendOneByteRecord = @"GCDAsyncSocketSSLSessionOptionSendOneByteRecord";
127
NSString *const GCDAsyncSocketSSLCipherSuites = @"GCDAsyncSocketSSLCipherSuites";
128
NSString *const GCDAsyncSocketSSLALPN = @"GCDAsyncSocketSSLALPN";
129
#if !TARGET_OS_IPHONE
130
NSString *const GCDAsyncSocketSSLDiffieHellmanParameters = @"GCDAsyncSocketSSLDiffieHellmanParameters";
131
#endif
132
 
133
enum GCDAsyncSocketFlags
134
{
135
        kSocketStarted                 = 1 <<  0,  // If set, socket has been started (accepting/connecting)
136
        kConnected                     = 1 <<  1,  // If set, the socket is connected
137
        kForbidReadsWrites             = 1 <<  2,  // If set, no new reads or writes are allowed
138
        kReadsPaused                   = 1 <<  3,  // If set, reads are paused due to possible timeout
139
        kWritesPaused                  = 1 <<  4,  // If set, writes are paused due to possible timeout
140
        kDisconnectAfterReads          = 1 <<  5,  // If set, disconnect after no more reads are queued
141
        kDisconnectAfterWrites         = 1 <<  6,  // If set, disconnect after no more writes are queued
142
        kSocketCanAcceptBytes          = 1 <<  7,  // If set, we know socket can accept bytes. If unset, it's unknown.
143
        kReadSourceSuspended           = 1 <<  8,  // If set, the read source is suspended
144
        kWriteSourceSuspended          = 1 <<  9,  // If set, the write source is suspended
145
        kQueuedTLS                     = 1 << 10,  // If set, we've queued an upgrade to TLS
146
        kStartingReadTLS               = 1 << 11,  // If set, we're waiting for TLS negotiation to complete
147
        kStartingWriteTLS              = 1 << 12,  // If set, we're waiting for TLS negotiation to complete
148
        kSocketSecure                  = 1 << 13,  // If set, socket is using secure communication via SSL/TLS
149
        kSocketHasReadEOF              = 1 << 14,  // If set, we have read EOF from socket
150
        kReadStreamClosed              = 1 << 15,  // If set, we've read EOF plus prebuffer has been drained
151
        kDealloc                       = 1 << 16,  // If set, the socket is being deallocated
152
#if TARGET_OS_IPHONE
153
        kAddedStreamsToRunLoop         = 1 << 17,  // If set, CFStreams have been added to listener thread
154
        kUsingCFStreamForTLS           = 1 << 18,  // If set, we're forced to use CFStream instead of SecureTransport
155
        kSecureSocketHasBytesAvailable = 1 << 19,  // If set, CFReadStream has notified us of bytes available
156
#endif
157
};
158
 
159
enum GCDAsyncSocketConfig
160
{
161
        kIPv4Disabled              = 1 << 0,  // If set, IPv4 is disabled
162
        kIPv6Disabled              = 1 << 1,  // If set, IPv6 is disabled
163
        kPreferIPv6                = 1 << 2,  // If set, IPv6 is preferred over IPv4
164
        kAllowHalfDuplexConnection = 1 << 3,  // If set, the socket will stay open even if the read stream closes
165
};
166
 
167
#if TARGET_OS_IPHONE
168
  static NSThread *cfstreamThread;  // Used for CFStreams
169
 
170
 
171
  static uint64_t cfstreamThreadRetainCount;   // setup & teardown
172
  static dispatch_queue_t cfstreamThreadSetupQueue; // setup & teardown
173
#endif
174
 
175
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
176
#pragma mark -
177
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
178
 
179
/**
180
 * A PreBuffer is used when there is more data available on the socket
181
 * than is being requested by current read request.
182
 * In this case we slurp up all data from the socket (to minimize sys calls),
183
 * and store additional yet unread data in a "prebuffer".
184
 *
185
 * The prebuffer is entirely drained before we read from the socket again.
186
 * In other words, a large chunk of data is written is written to the prebuffer.
187
 * The prebuffer is then drained via a series of one or more reads (for subsequent read request(s)).
188
 *
189
 * A ring buffer was once used for this purpose.
190
 * But a ring buffer takes up twice as much memory as needed (double the size for mirroring).
191
 * In fact, it generally takes up more than twice the needed size as everything has to be rounded up to vm_page_size.
192
 * And since the prebuffer is always completely drained after being written to, a full ring buffer isn't needed.
193
 *
194
 * The current design is very simple and straight-forward, while also keeping memory requirements lower.
195
**/
196
 
197
@interface GCDAsyncSocketPreBuffer : NSObject
198
{
199
        uint8_t *preBuffer;
200
        size_t preBufferSize;
201
 
202
        uint8_t *readPointer;
203
        uint8_t *writePointer;
204
}
205
 
206
- (instancetype)initWithCapacity:(size_t)numBytes NS_DESIGNATED_INITIALIZER;
207
 
208
- (void)ensureCapacityForWrite:(size_t)numBytes;
209
 
210
- (size_t)availableBytes;
211
- (uint8_t *)readBuffer;
212
 
213
- (void)getReadBuffer:(uint8_t **)bufferPtr availableBytes:(size_t *)availableBytesPtr;
214
 
215
- (size_t)availableSpace;
216
- (uint8_t *)writeBuffer;
217
 
218
- (void)getWriteBuffer:(uint8_t **)bufferPtr availableSpace:(size_t *)availableSpacePtr;
219
 
220
- (void)didRead:(size_t)bytesRead;
221
- (void)didWrite:(size_t)bytesWritten;
222
 
223
- (void)reset;
224
 
225
@end
226
 
227
@implementation GCDAsyncSocketPreBuffer
228
 
229
// Cover the superclass' designated initializer
230
- (instancetype)init NS_UNAVAILABLE
231
{
232
        NSAssert(0, @"Use the designated initializer");
233
        return nil;
234
}
235
 
236
- (instancetype)initWithCapacity:(size_t)numBytes
237
{
238
        if ((self = [super init]))
239
        {
240
                preBufferSize = numBytes;
241
                preBuffer = malloc(preBufferSize);
242
 
243
                readPointer = preBuffer;
244
                writePointer = preBuffer;
245
        }
246
        return self;
247
}
248
 
249
- (void)dealloc
250
{
251
        if (preBuffer)
252
                free(preBuffer);
253
}
254
 
255
- (void)ensureCapacityForWrite:(size_t)numBytes
256
{
257
        size_t availableSpace = [self availableSpace];
258
 
259
        if (numBytes > availableSpace)
260
        {
261
                size_t additionalBytes = numBytes - availableSpace;
262
 
263
                size_t newPreBufferSize = preBufferSize + additionalBytes;
264
                uint8_t *newPreBuffer = realloc(preBuffer, newPreBufferSize);
265
 
266
                size_t readPointerOffset = readPointer - preBuffer;
267
                size_t writePointerOffset = writePointer - preBuffer;
268
 
269
                preBuffer = newPreBuffer;
270
                preBufferSize = newPreBufferSize;
271
 
272
                readPointer = preBuffer + readPointerOffset;
273
                writePointer = preBuffer + writePointerOffset;
274
        }
275
}
276
 
277
- (size_t)availableBytes
278
{
279
        return writePointer - readPointer;
280
}
281
 
282
- (uint8_t *)readBuffer
283
{
284
        return readPointer;
285
}
286
 
287
- (void)getReadBuffer:(uint8_t **)bufferPtr availableBytes:(size_t *)availableBytesPtr
288
{
289
        if (bufferPtr) *bufferPtr = readPointer;
290
        if (availableBytesPtr) *availableBytesPtr = [self availableBytes];
291
}
292
 
293
- (void)didRead:(size_t)bytesRead
294
{
295
        readPointer += bytesRead;
296
 
297
        if (readPointer == writePointer)
298
        {
299
                // The prebuffer has been drained. Reset pointers.
300
                readPointer  = preBuffer;
301
                writePointer = preBuffer;
302
        }
303
}
304
 
305
- (size_t)availableSpace
306
{
307
        return preBufferSize - (writePointer - preBuffer);
308
}
309
 
310
- (uint8_t *)writeBuffer
311
{
312
        return writePointer;
313
}
314
 
315
- (void)getWriteBuffer:(uint8_t **)bufferPtr availableSpace:(size_t *)availableSpacePtr
316
{
317
        if (bufferPtr) *bufferPtr = writePointer;
318
        if (availableSpacePtr) *availableSpacePtr = [self availableSpace];
319
}
320
 
321
- (void)didWrite:(size_t)bytesWritten
322
{
323
        writePointer += bytesWritten;
324
}
325
 
326
- (void)reset
327
{
328
        readPointer  = preBuffer;
329
        writePointer = preBuffer;
330
}
331
 
332
@end
333
 
334
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
335
#pragma mark -
336
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
337
 
338
/**
339
 * The GCDAsyncReadPacket encompasses the instructions for any given read.
340
 * The content of a read packet allows the code to determine if we're:
341
 *  - reading to a certain length
342
 *  - reading to a certain separator
343
 *  - or simply reading the first chunk of available data
344
**/
345
@interface GCDAsyncReadPacket : NSObject
346
{
347
  @public
348
        NSMutableData *buffer;
349
        NSUInteger startOffset;
350
        NSUInteger bytesDone;
351
        NSUInteger maxLength;
352
        NSTimeInterval timeout;
353
        NSUInteger readLength;
354
        NSData *term;
355
        BOOL bufferOwner;
356
        NSUInteger originalBufferLength;
357
        long tag;
358
}
359
- (instancetype)initWithData:(NSMutableData *)d
360
                 startOffset:(NSUInteger)s
361
                   maxLength:(NSUInteger)m
362
                     timeout:(NSTimeInterval)t
363
                  readLength:(NSUInteger)l
364
                  terminator:(NSData *)e
365
                         tag:(long)i NS_DESIGNATED_INITIALIZER;
366
 
367
- (void)ensureCapacityForAdditionalDataOfLength:(NSUInteger)bytesToRead;
368
 
369
- (NSUInteger)optimalReadLengthWithDefault:(NSUInteger)defaultValue shouldPreBuffer:(BOOL *)shouldPreBufferPtr;
370
 
371
- (NSUInteger)readLengthForNonTermWithHint:(NSUInteger)bytesAvailable;
372
- (NSUInteger)readLengthForTermWithHint:(NSUInteger)bytesAvailable shouldPreBuffer:(BOOL *)shouldPreBufferPtr;
373
- (NSUInteger)readLengthForTermWithPreBuffer:(GCDAsyncSocketPreBuffer *)preBuffer found:(BOOL *)foundPtr;
374
 
375
- (NSInteger)searchForTermAfterPreBuffering:(ssize_t)numBytes;
376
 
377
@end
378
 
379
@implementation GCDAsyncReadPacket
380
 
381
// Cover the superclass' designated initializer
382
- (instancetype)init NS_UNAVAILABLE
383
{
384
        NSAssert(0, @"Use the designated initializer");
385
        return nil;
386
}
387
 
388
- (instancetype)initWithData:(NSMutableData *)d
389
                 startOffset:(NSUInteger)s
390
                   maxLength:(NSUInteger)m
391
                     timeout:(NSTimeInterval)t
392
                  readLength:(NSUInteger)l
393
                  terminator:(NSData *)e
394
                         tag:(long)i
395
{
396
        if((self = [super init]))
397
        {
398
                bytesDone = 0;
399
                maxLength = m;
400
                timeout = t;
401
                readLength = l;
402
                term = [e copy];
403
                tag = i;
404
 
405
                if (d)
406
                {
407
                        buffer = d;
408
                        startOffset = s;
409
                        bufferOwner = NO;
410
                        originalBufferLength = [d length];
411
                }
412
                else
413
                {
414
                        if (readLength > 0)
415
                                buffer = [[NSMutableData alloc] initWithLength:readLength];
416
                        else
417
                                buffer = [[NSMutableData alloc] initWithLength:0];
418
 
419
                        startOffset = 0;
420
                        bufferOwner = YES;
421
                        originalBufferLength = 0;
422
                }
423
        }
424
        return self;
425
}
426
 
427
/**
428
 * Increases the length of the buffer (if needed) to ensure a read of the given size will fit.
429
**/
430
- (void)ensureCapacityForAdditionalDataOfLength:(NSUInteger)bytesToRead
431
{
432
        NSUInteger buffSize = [buffer length];
433
        NSUInteger buffUsed = startOffset + bytesDone;
434
 
435
        NSUInteger buffSpace = buffSize - buffUsed;
436
 
437
        if (bytesToRead > buffSpace)
438
        {
439
                NSUInteger buffInc = bytesToRead - buffSpace;
440
 
441
                [buffer increaseLengthBy:buffInc];
442
        }
443
}
444
 
445
/**
446
 * This method is used when we do NOT know how much data is available to be read from the socket.
447
 * This method returns the default value unless it exceeds the specified readLength or maxLength.
448
 *
449
 * Furthermore, the shouldPreBuffer decision is based upon the packet type,
450
 * and whether the returned value would fit in the current buffer without requiring a resize of the buffer.
451
**/
452
- (NSUInteger)optimalReadLengthWithDefault:(NSUInteger)defaultValue shouldPreBuffer:(BOOL *)shouldPreBufferPtr
453
{
454
        NSUInteger result;
455
 
456
        if (readLength > 0)
457
        {
458
                // Read a specific length of data
459
                result = readLength - bytesDone;
460
 
461
                // There is no need to prebuffer since we know exactly how much data we need to read.
462
                // Even if the buffer isn't currently big enough to fit this amount of data,
463
                // it would have to be resized eventually anyway.
464
 
465
                if (shouldPreBufferPtr)
466
                        *shouldPreBufferPtr = NO;
467
        }
468
        else
469
        {
470
                // Either reading until we find a specified terminator,
471
                // or we're simply reading all available data.
472
                //
473
                // In other words, one of:
474
                //
475
                // - readDataToData packet
476
                // - readDataWithTimeout packet
477
 
478
                if (maxLength > 0)
479
                        result =  MIN(defaultValue, (maxLength - bytesDone));
480
                else
481
                        result = defaultValue;
482
 
483
                // Since we don't know the size of the read in advance,
484
                // the shouldPreBuffer decision is based upon whether the returned value would fit
485
                // in the current buffer without requiring a resize of the buffer.
486
                //
487
                // This is because, in all likelyhood, the amount read from the socket will be less than the default value.
488
                // Thus we should avoid over-allocating the read buffer when we can simply use the pre-buffer instead.
489
 
490
                if (shouldPreBufferPtr)
491
                {
492
                        NSUInteger buffSize = [buffer length];
493
                        NSUInteger buffUsed = startOffset + bytesDone;
494
 
495
                        NSUInteger buffSpace = buffSize - buffUsed;
496
 
497
                        if (buffSpace >= result)
498
                                *shouldPreBufferPtr = NO;
499
                        else
500
                                *shouldPreBufferPtr = YES;
501
                }
502
        }
503
 
504
        return result;
505
}
506
 
507
/**
508
 * For read packets without a set terminator, returns the amount of data
509
 * that can be read without exceeding the readLength or maxLength.
510
 *
511
 * The given parameter indicates the number of bytes estimated to be available on the socket,
512
 * which is taken into consideration during the calculation.
513
 *
514
 * The given hint MUST be greater than zero.
515
**/
516
- (NSUInteger)readLengthForNonTermWithHint:(NSUInteger)bytesAvailable
517
{
518
        NSAssert(term == nil, @"This method does not apply to term reads");
519
        NSAssert(bytesAvailable > 0, @"Invalid parameter: bytesAvailable");
520
 
521
        if (readLength > 0)
522
        {
523
                // Read a specific length of data
524
 
525
                return MIN(bytesAvailable, (readLength - bytesDone));
526
 
527
                // No need to avoid resizing the buffer.
528
                // If the user provided their own buffer,
529
                // and told us to read a certain length of data that exceeds the size of the buffer,
530
                // then it is clear that our code will resize the buffer during the read operation.
531
                //
532
                // This method does not actually do any resizing.
533
                // The resizing will happen elsewhere if needed.
534
        }
535
        else
536
        {
537
                // Read all available data
538
 
539
                NSUInteger result = bytesAvailable;
540
 
541
                if (maxLength > 0)
542
                {
543
                        result = MIN(result, (maxLength - bytesDone));
544
                }
545
 
546
                // No need to avoid resizing the buffer.
547
                // If the user provided their own buffer,
548
                // and told us to read all available data without giving us a maxLength,
549
                // then it is clear that our code might resize the buffer during the read operation.
550
                //
551
                // This method does not actually do any resizing.
552
                // The resizing will happen elsewhere if needed.
553
 
554
                return result;
555
        }
556
}
557
 
558
/**
559
 * For read packets with a set terminator, returns the amount of data
560
 * that can be read without exceeding the maxLength.
561
 *
562
 * The given parameter indicates the number of bytes estimated to be available on the socket,
563
 * which is taken into consideration during the calculation.
564
 *
565
 * To optimize memory allocations, mem copies, and mem moves
566
 * the shouldPreBuffer boolean value will indicate if the data should be read into a prebuffer first,
567
 * or if the data can be read directly into the read packet's buffer.
568
**/
569
- (NSUInteger)readLengthForTermWithHint:(NSUInteger)bytesAvailable shouldPreBuffer:(BOOL *)shouldPreBufferPtr
570
{
571
        NSAssert(term != nil, @"This method does not apply to non-term reads");
572
        NSAssert(bytesAvailable > 0, @"Invalid parameter: bytesAvailable");
573
 
574
 
575
        NSUInteger result = bytesAvailable;
576
 
577
        if (maxLength > 0)
578
        {
579
                result = MIN(result, (maxLength - bytesDone));
580
        }
581
 
582
        // Should the data be read into the read packet's buffer, or into a pre-buffer first?
583
        //
584
        // One would imagine the preferred option is the faster one.
585
        // So which one is faster?
586
        //
587
        // Reading directly into the packet's buffer requires:
588
        // 1. Possibly resizing packet buffer (malloc/realloc)
589
        // 2. Filling buffer (read)
590
        // 3. Searching for term (memcmp)
591
        // 4. Possibly copying overflow into prebuffer (malloc/realloc, memcpy)
592
        //
593
        // Reading into prebuffer first:
594
        // 1. Possibly resizing prebuffer (malloc/realloc)
595
        // 2. Filling buffer (read)
596
        // 3. Searching for term (memcmp)
597
        // 4. Copying underflow into packet buffer (malloc/realloc, memcpy)
598
        // 5. Removing underflow from prebuffer (memmove)
599
        //
600
        // Comparing the performance of the two we can see that reading
601
        // data into the prebuffer first is slower due to the extra memove.
602
        //
603
        // However:
604
        // The implementation of NSMutableData is open source via core foundation's CFMutableData.
605
        // Decreasing the length of a mutable data object doesn't cause a realloc.
606
        // In other words, the capacity of a mutable data object can grow, but doesn't shrink.
607
        //
608
        // This means the prebuffer will rarely need a realloc.
609
        // The packet buffer, on the other hand, may often need a realloc.
610
        // This is especially true if we are the buffer owner.
611
        // Furthermore, if we are constantly realloc'ing the packet buffer,
612
        // and then moving the overflow into the prebuffer,
613
        // then we're consistently over-allocating memory for each term read.
614
        // And now we get into a bit of a tradeoff between speed and memory utilization.
615
        //
616
        // The end result is that the two perform very similarly.
617
        // And we can answer the original question very simply by another means.
618
        //
619
        // If we can read all the data directly into the packet's buffer without resizing it first,
620
        // then we do so. Otherwise we use the prebuffer.
621
 
622
        if (shouldPreBufferPtr)
623
        {
624
                NSUInteger buffSize = [buffer length];
625
                NSUInteger buffUsed = startOffset + bytesDone;
626
 
627
                if ((buffSize - buffUsed) >= result)
628
                        *shouldPreBufferPtr = NO;
629
                else
630
                        *shouldPreBufferPtr = YES;
631
        }
632
 
633
        return result;
634
}
635
 
636
/**
637
 * For read packets with a set terminator,
638
 * returns the amount of data that can be read from the given preBuffer,
639
 * without going over a terminator or the maxLength.
640
 *
641
 * It is assumed the terminator has not already been read.
642
**/
643
- (NSUInteger)readLengthForTermWithPreBuffer:(GCDAsyncSocketPreBuffer *)preBuffer found:(BOOL *)foundPtr
644
{
645
        NSAssert(term != nil, @"This method does not apply to non-term reads");
646
        NSAssert([preBuffer availableBytes] > 0, @"Invoked with empty pre buffer!");
647
 
648
        // We know that the terminator, as a whole, doesn't exist in our own buffer.
649
        // But it is possible that a _portion_ of it exists in our buffer.
650
        // So we're going to look for the terminator starting with a portion of our own buffer.
651
        //
652
        // Example:
653
        //
654
        // term length      = 3 bytes
655
        // bytesDone        = 5 bytes
656
        // preBuffer length = 5 bytes
657
        //
658
        // If we append the preBuffer to our buffer,
659
        // it would look like this:
660
        //
661
        // ---------------------
662
        // |B|B|B|B|B|P|P|P|P|P|
663
        // ---------------------
664
        //
665
        // So we start our search here:
666
        //
667
        // ---------------------
668
        // |B|B|B|B|B|P|P|P|P|P|
669
        // -------^-^-^---------
670
        //
671
        // And move forwards...
672
        //
673
        // ---------------------
674
        // |B|B|B|B|B|P|P|P|P|P|
675
        // ---------^-^-^-------
676
        //
677
        // Until we find the terminator or reach the end.
678
        //
679
        // ---------------------
680
        // |B|B|B|B|B|P|P|P|P|P|
681
        // ---------------^-^-^-
682
 
683
        BOOL found = NO;
684
 
685
        NSUInteger termLength = [term length];
686
        NSUInteger preBufferLength = [preBuffer availableBytes];
687
 
688
        if ((bytesDone + preBufferLength) < termLength)
689
        {
690
                // Not enough data for a full term sequence yet
691
                return preBufferLength;
692
        }
693
 
694
        NSUInteger maxPreBufferLength;
695
        if (maxLength > 0) {
696
                maxPreBufferLength = MIN(preBufferLength, (maxLength - bytesDone));
697
 
698
                // Note: maxLength >= termLength
699
        }
700
        else {
701
                maxPreBufferLength = preBufferLength;
702
        }
703
 
704
        uint8_t seq[termLength];
705
        const void *termBuf = [term bytes];
706
 
707
        NSUInteger bufLen = MIN(bytesDone, (termLength - 1));
708
        uint8_t *buf = (uint8_t *)[buffer mutableBytes] + startOffset + bytesDone - bufLen;
709
 
710
        NSUInteger preLen = termLength - bufLen;
711
        const uint8_t *pre = [preBuffer readBuffer];
712
 
713
        NSUInteger loopCount = bufLen + maxPreBufferLength - termLength + 1; // Plus one. See example above.
714
 
715
        NSUInteger result = maxPreBufferLength;
716
 
717
        NSUInteger i;
718
        for (i = 0; i < loopCount; i++)
719
        {
720
                if (bufLen > 0)
721
                {
722
                        // Combining bytes from buffer and preBuffer
723
 
724
                        memcpy(seq, buf, bufLen);
725
                        memcpy(seq + bufLen, pre, preLen);
726
 
727
                        if (memcmp(seq, termBuf, termLength) == 0)
728
                        {
729
                                result = preLen;
730
                                found = YES;
731
                                break;
732
                        }
733
 
734
                        buf++;
735
                        bufLen--;
736
                        preLen++;
737
                }
738
                else
739
                {
740
                        // Comparing directly from preBuffer
741
 
742
                        if (memcmp(pre, termBuf, termLength) == 0)
743
                        {
744
                                NSUInteger preOffset = pre - [preBuffer readBuffer]; // pointer arithmetic
745
 
746
                                result = preOffset + termLength;
747
                                found = YES;
748
                                break;
749
                        }
750
 
751
                        pre++;
752
                }
753
        }
754
 
755
        // There is no need to avoid resizing the buffer in this particular situation.
756
 
757
        if (foundPtr) *foundPtr = found;
758
        return result;
759
}
760
 
761
/**
762
 * For read packets with a set terminator, scans the packet buffer for the term.
763
 * It is assumed the terminator had not been fully read prior to the new bytes.
764
 *
765
 * If the term is found, the number of excess bytes after the term are returned.
766
 * If the term is not found, this method will return -1.
767
 *
768
 * Note: A return value of zero means the term was found at the very end.
769
 *
770
 * Prerequisites:
771
 * The given number of bytes have been added to the end of our buffer.
772
 * Our bytesDone variable has NOT been changed due to the prebuffered bytes.
773
**/
774
- (NSInteger)searchForTermAfterPreBuffering:(ssize_t)numBytes
775
{
776
        NSAssert(term != nil, @"This method does not apply to non-term reads");
777
 
778
        // The implementation of this method is very similar to the above method.
779
        // See the above method for a discussion of the algorithm used here.
780
 
781
        uint8_t *buff = [buffer mutableBytes];
782
        NSUInteger buffLength = bytesDone + numBytes;
783
 
784
        const void *termBuff = [term bytes];
785
        NSUInteger termLength = [term length];
786
 
787
        // Note: We are dealing with unsigned integers,
788
        // so make sure the math doesn't go below zero.
789
 
790
        NSUInteger i = ((buffLength - numBytes) >= termLength) ? (buffLength - numBytes - termLength + 1) : 0;
791
 
792
        while (i + termLength <= buffLength)
793
        {
794
                uint8_t *subBuffer = buff + startOffset + i;
795
 
796
                if (memcmp(subBuffer, termBuff, termLength) == 0)
797
                {
798
                        return buffLength - (i + termLength);
799
                }
800
 
801
                i++;
802
        }
803
 
804
        return -1;
805
}
806
 
807
 
808
@end
809
 
810
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
811
#pragma mark -
812
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
813
 
814
/**
815
 * The GCDAsyncWritePacket encompasses the instructions for any given write.
816
**/
817
@interface GCDAsyncWritePacket : NSObject
818
{
819
  @public
820
        NSData *buffer;
821
        NSUInteger bytesDone;
822
        long tag;
823
        NSTimeInterval timeout;
824
}
825
- (instancetype)initWithData:(NSData *)d timeout:(NSTimeInterval)t tag:(long)i NS_DESIGNATED_INITIALIZER;
826
@end
827
 
828
@implementation GCDAsyncWritePacket
829
 
830
// Cover the superclass' designated initializer
831
- (instancetype)init NS_UNAVAILABLE
832
{
833
        NSAssert(0, @"Use the designated initializer");
834
        return nil;
835
}
836
 
837
- (instancetype)initWithData:(NSData *)d timeout:(NSTimeInterval)t tag:(long)i
838
{
839
        if((self = [super init]))
840
        {
841
                buffer = d; // Retain not copy. For performance as documented in header file.
842
                bytesDone = 0;
843
                timeout = t;
844
                tag = i;
845
        }
846
        return self;
847
}
848
 
849
 
850
@end
851
 
852
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
853
#pragma mark -
854
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
855
 
856
/**
857
 * The GCDAsyncSpecialPacket encompasses special instructions for interruptions in the read/write queues.
858
 * This class my be altered to support more than just TLS in the future.
859
**/
860
@interface GCDAsyncSpecialPacket : NSObject
861
{
862
  @public
863
        NSDictionary *tlsSettings;
864
}
865
- (instancetype)initWithTLSSettings:(NSDictionary <NSString*,NSObject*>*)settings NS_DESIGNATED_INITIALIZER;
866
@end
867
 
868
@implementation GCDAsyncSpecialPacket
869
 
870
// Cover the superclass' designated initializer
871
- (instancetype)init NS_UNAVAILABLE
872
{
873
        NSAssert(0, @"Use the designated initializer");
874
        return nil;
875
}
876
 
877
- (instancetype)initWithTLSSettings:(NSDictionary <NSString*,NSObject*>*)settings
878
{
879
        if((self = [super init]))
880
        {
881
                tlsSettings = [settings copy];
882
        }
883
        return self;
884
}
885
 
886
 
887
@end
888
 
889
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
890
#pragma mark -
891
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
892
 
893
@implementation GCDAsyncSocket
894
{
895
        uint32_t flags;
896
        uint16_t config;
897
 
898
        __weak id<GCDAsyncSocketDelegate> delegate;
899
        dispatch_queue_t delegateQueue;
900
 
901
        int socket4FD;
902
        int socket6FD;
903
        int socketUN;
904
        NSURL *socketUrl;
905
        int stateIndex;
906
        NSData * connectInterface4;
907
        NSData * connectInterface6;
908
        NSData * connectInterfaceUN;
909
 
910
        dispatch_queue_t socketQueue;
911
 
912
        dispatch_source_t accept4Source;
913
        dispatch_source_t accept6Source;
914
        dispatch_source_t acceptUNSource;
915
        dispatch_source_t connectTimer;
916
        dispatch_source_t readSource;
917
        dispatch_source_t writeSource;
918
        dispatch_source_t readTimer;
919
        dispatch_source_t writeTimer;
920
 
921
        NSMutableArray *readQueue;
922
        NSMutableArray *writeQueue;
923
 
924
        GCDAsyncReadPacket *currentRead;
925
        GCDAsyncWritePacket *currentWrite;
926
 
927
        unsigned long socketFDBytesAvailable;
928
 
929
        GCDAsyncSocketPreBuffer *preBuffer;
930
 
931
#if TARGET_OS_IPHONE
932
        CFStreamClientContext streamContext;
933
        CFReadStreamRef readStream;
934
        CFWriteStreamRef writeStream;
935
#endif
936
        SSLContextRef sslContext;
937
        GCDAsyncSocketPreBuffer *sslPreBuffer;
938
        size_t sslWriteCachedLength;
939
        OSStatus sslErrCode;
940
    OSStatus lastSSLHandshakeError;
941
 
942
        void *IsOnSocketQueueOrTargetQueueKey;
943
 
944
        id userData;
945
    NSTimeInterval alternateAddressDelay;
946
}
947
 
948
- (instancetype)init
949
{
950
        return [self initWithDelegate:nil delegateQueue:NULL socketQueue:NULL];
951
}
952
 
953
- (instancetype)initWithSocketQueue:(dispatch_queue_t)sq
954
{
955
        return [self initWithDelegate:nil delegateQueue:NULL socketQueue:sq];
956
}
957
 
958
- (instancetype)initWithDelegate:(id<GCDAsyncSocketDelegate>)aDelegate delegateQueue:(dispatch_queue_t)dq
959
{
960
        return [self initWithDelegate:aDelegate delegateQueue:dq socketQueue:NULL];
961
}
962
 
963
- (instancetype)initWithDelegate:(id<GCDAsyncSocketDelegate>)aDelegate delegateQueue:(dispatch_queue_t)dq socketQueue:(dispatch_queue_t)sq
964
{
965
        if((self = [super init]))
966
        {
967
                delegate = aDelegate;
968
                delegateQueue = dq;
969
 
970
                #if !OS_OBJECT_USE_OBJC
971
                if (dq) dispatch_retain(dq);
972
                #endif
973
 
974
                socket4FD = SOCKET_NULL;
975
                socket6FD = SOCKET_NULL;
976
                socketUN = SOCKET_NULL;
977
                socketUrl = nil;
978
                stateIndex = 0;
979
 
980
                if (sq)
981
                {
982
                        NSAssert(sq != dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0),
983
                                 @"The given socketQueue parameter must not be a concurrent queue.");
984
                        NSAssert(sq != dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0),
985
                                 @"The given socketQueue parameter must not be a concurrent queue.");
986
                        NSAssert(sq != dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),
987
                                 @"The given socketQueue parameter must not be a concurrent queue.");
988
 
989
                        socketQueue = sq;
990
                        #if !OS_OBJECT_USE_OBJC
991
                        dispatch_retain(sq);
992
                        #endif
993
                }
994
                else
995
                {
996
                        socketQueue = dispatch_queue_create([GCDAsyncSocketQueueName UTF8String], NULL);
997
                }
998
 
999
                // The dispatch_queue_set_specific() and dispatch_get_specific() functions take a "void *key" parameter.
1000
                // From the documentation:
1001
                //
1002
                // > Keys are only compared as pointers and are never dereferenced.
1003
                // > Thus, you can use a pointer to a static variable for a specific subsystem or
1004
                // > any other value that allows you to identify the value uniquely.
1005
                //
1006
                // We're just going to use the memory address of an ivar.
1007
                // Specifically an ivar that is explicitly named for our purpose to make the code more readable.
1008
                //
1009
                // However, it feels tedious (and less readable) to include the "&" all the time:
1010
                // dispatch_get_specific(&IsOnSocketQueueOrTargetQueueKey)
1011
                //
1012
                // So we're going to make it so it doesn't matter if we use the '&' or not,
1013
                // by assigning the value of the ivar to the address of the ivar.
1014
                // Thus: IsOnSocketQueueOrTargetQueueKey == &IsOnSocketQueueOrTargetQueueKey;
1015
 
1016
                IsOnSocketQueueOrTargetQueueKey = &IsOnSocketQueueOrTargetQueueKey;
1017
 
1018
                void *nonNullUnusedPointer = (__bridge void *)self;
1019
                dispatch_queue_set_specific(socketQueue, IsOnSocketQueueOrTargetQueueKey, nonNullUnusedPointer, NULL);
1020
 
1021
                readQueue = [[NSMutableArray alloc] initWithCapacity:5];
1022
                currentRead = nil;
1023
 
1024
                writeQueue = [[NSMutableArray alloc] initWithCapacity:5];
1025
                currentWrite = nil;
1026
 
1027
                preBuffer = [[GCDAsyncSocketPreBuffer alloc] initWithCapacity:(1024 * 4)];
1028
        alternateAddressDelay = 0.3;
1029
        }
1030
        return self;
1031
}
1032
 
1033
- (void)dealloc
1034
{
1035
        LogInfo(@"%@ - %@ (start)", THIS_METHOD, self);
1036
 
1037
        // Set dealloc flag.
1038
        // This is used by closeWithError to ensure we don't accidentally retain ourself.
1039
        flags |= kDealloc;
1040
 
1041
        if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
1042
        {
1043
                [self closeWithError:nil];
1044
        }
1045
        else
1046
        {
1047
                dispatch_sync(socketQueue, ^{
1048
                        [self closeWithError:nil];
1049
                });
1050
        }
1051
 
1052
        delegate = nil;
1053
 
1054
        #if !OS_OBJECT_USE_OBJC
1055
        if (delegateQueue) dispatch_release(delegateQueue);
1056
        #endif
1057
        delegateQueue = NULL;
1058
 
1059
        #if !OS_OBJECT_USE_OBJC
1060
        if (socketQueue) dispatch_release(socketQueue);
1061
        #endif
1062
        socketQueue = NULL;
1063
 
1064
        LogInfo(@"%@ - %@ (finish)", THIS_METHOD, self);
1065
}
1066
 
1067
#pragma mark -
1068
 
1069
+ (nullable instancetype)socketFromConnectedSocketFD:(int)socketFD socketQueue:(nullable dispatch_queue_t)sq error:(NSError**)error {
1070
  return [self socketFromConnectedSocketFD:socketFD delegate:nil delegateQueue:NULL socketQueue:sq error:error];
1071
}
1072
 
1073
+ (nullable instancetype)socketFromConnectedSocketFD:(int)socketFD delegate:(nullable id<GCDAsyncSocketDelegate>)aDelegate delegateQueue:(nullable dispatch_queue_t)dq error:(NSError**)error {
1074
  return [self socketFromConnectedSocketFD:socketFD delegate:aDelegate delegateQueue:dq socketQueue:NULL error:error];
1075
}
1076
 
1077
+ (nullable instancetype)socketFromConnectedSocketFD:(int)socketFD delegate:(nullable id<GCDAsyncSocketDelegate>)aDelegate delegateQueue:(nullable dispatch_queue_t)dq socketQueue:(nullable dispatch_queue_t)sq error:(NSError* __autoreleasing *)error
1078
{
1079
  __block BOOL errorOccured = NO;
1080
 
1081
  GCDAsyncSocket *socket = [[[self class] alloc] initWithDelegate:aDelegate delegateQueue:dq socketQueue:sq];
1082
 
1083
  dispatch_sync(socket->socketQueue, ^{ @autoreleasepool {
1084
    struct sockaddr addr;
1085
    socklen_t addr_size = sizeof(struct sockaddr);
1086
    int retVal = getpeername(socketFD, (struct sockaddr *)&addr, &addr_size);
1087
    if (retVal)
1088
    {
1089
      NSString *errMsg = NSLocalizedStringWithDefaultValue(@"GCDAsyncSocketOtherError",
1090
                                                           @"GCDAsyncSocket", [NSBundle mainBundle],
1091
                                                           @"Attempt to create socket from socket FD failed. getpeername() failed", nil);
1092
 
1093
      NSDictionary *userInfo = @{NSLocalizedDescriptionKey : errMsg};
1094
 
1095
      errorOccured = YES;
1096
      if (error)
1097
        *error = [NSError errorWithDomain:GCDAsyncSocketErrorDomain code:GCDAsyncSocketOtherError userInfo:userInfo];
1098
      return;
1099
    }
1100
 
1101
    if (addr.sa_family == AF_INET)
1102
    {
1103
      socket->socket4FD = socketFD;
1104
    }
1105
    else if (addr.sa_family == AF_INET6)
1106
    {
1107
      socket->socket6FD = socketFD;
1108
    }
1109
    else
1110
    {
1111
      NSString *errMsg = NSLocalizedStringWithDefaultValue(@"GCDAsyncSocketOtherError",
1112
                                                           @"GCDAsyncSocket", [NSBundle mainBundle],
1113
                                                           @"Attempt to create socket from socket FD failed. socket FD is neither IPv4 nor IPv6", nil);
1114
 
1115
      NSDictionary *userInfo = @{NSLocalizedDescriptionKey : errMsg};
1116
 
1117
      errorOccured = YES;
1118
      if (error)
1119
        *error = [NSError errorWithDomain:GCDAsyncSocketErrorDomain code:GCDAsyncSocketOtherError userInfo:userInfo];
1120
      return;
1121
    }
1122
 
1123
    socket->flags = kSocketStarted;
1124
    [socket didConnect:socket->stateIndex];
1125
  }});
1126
 
1127
  return errorOccured? nil: socket;
1128
}
1129
 
1130
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1131
#pragma mark Configuration
1132
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1133
 
1134
- (id)delegate
1135
{
1136
        if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
1137
        {
1138
                return delegate;
1139
        }
1140
        else
1141
        {
1142
                __block id result;
1143
 
1144
                dispatch_sync(socketQueue, ^{
1145
            result = self->delegate;
1146
                });
1147
 
1148
                return result;
1149
        }
1150
}
1151
 
1152
- (void)setDelegate:(id)newDelegate synchronously:(BOOL)synchronously
1153
{
1154
        dispatch_block_t block = ^{
1155
        self->delegate = newDelegate;
1156
        };
1157
 
1158
        if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) {
1159
                block();
1160
        }
1161
        else {
1162
                if (synchronously)
1163
                        dispatch_sync(socketQueue, block);
1164
                else
1165
                        dispatch_async(socketQueue, block);
1166
        }
1167
}
1168
 
1169
- (void)setDelegate:(id<GCDAsyncSocketDelegate>)newDelegate
1170
{
1171
        [self setDelegate:newDelegate synchronously:NO];
1172
}
1173
 
1174
- (void)synchronouslySetDelegate:(id<GCDAsyncSocketDelegate>)newDelegate
1175
{
1176
        [self setDelegate:newDelegate synchronously:YES];
1177
}
1178
 
1179
- (dispatch_queue_t)delegateQueue
1180
{
1181
        if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
1182
        {
1183
                return delegateQueue;
1184
        }
1185
        else
1186
        {
1187
                __block dispatch_queue_t result;
1188
 
1189
                dispatch_sync(socketQueue, ^{
1190
            result = self->delegateQueue;
1191
                });
1192
 
1193
                return result;
1194
        }
1195
}
1196
 
1197
- (void)setDelegateQueue:(dispatch_queue_t)newDelegateQueue synchronously:(BOOL)synchronously
1198
{
1199
        dispatch_block_t block = ^{
1200
 
1201
                #if !OS_OBJECT_USE_OBJC
1202
        if (self->delegateQueue) dispatch_release(self->delegateQueue);
1203
                if (newDelegateQueue) dispatch_retain(newDelegateQueue);
1204
                #endif
1205
 
1206
        self->delegateQueue = newDelegateQueue;
1207
        };
1208
 
1209
        if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) {
1210
                block();
1211
        }
1212
        else {
1213
                if (synchronously)
1214
                        dispatch_sync(socketQueue, block);
1215
                else
1216
                        dispatch_async(socketQueue, block);
1217
        }
1218
}
1219
 
1220
- (void)setDelegateQueue:(dispatch_queue_t)newDelegateQueue
1221
{
1222
        [self setDelegateQueue:newDelegateQueue synchronously:NO];
1223
}
1224
 
1225
- (void)synchronouslySetDelegateQueue:(dispatch_queue_t)newDelegateQueue
1226
{
1227
        [self setDelegateQueue:newDelegateQueue synchronously:YES];
1228
}
1229
 
1230
- (void)getDelegate:(id<GCDAsyncSocketDelegate> *)delegatePtr delegateQueue:(dispatch_queue_t *)delegateQueuePtr
1231
{
1232
        if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
1233
        {
1234
                if (delegatePtr) *delegatePtr = delegate;
1235
                if (delegateQueuePtr) *delegateQueuePtr = delegateQueue;
1236
        }
1237
        else
1238
        {
1239
                __block id dPtr = NULL;
1240
                __block dispatch_queue_t dqPtr = NULL;
1241
 
1242
                dispatch_sync(socketQueue, ^{
1243
            dPtr = self->delegate;
1244
            dqPtr = self->delegateQueue;
1245
                });
1246
 
1247
                if (delegatePtr) *delegatePtr = dPtr;
1248
                if (delegateQueuePtr) *delegateQueuePtr = dqPtr;
1249
        }
1250
}
1251
 
1252
- (void)setDelegate:(id)newDelegate delegateQueue:(dispatch_queue_t)newDelegateQueue synchronously:(BOOL)synchronously
1253
{
1254
        dispatch_block_t block = ^{
1255
 
1256
        self->delegate = newDelegate;
1257
 
1258
                #if !OS_OBJECT_USE_OBJC
1259
        if (self->delegateQueue) dispatch_release(self->delegateQueue);
1260
                if (newDelegateQueue) dispatch_retain(newDelegateQueue);
1261
                #endif
1262
 
1263
        self->delegateQueue = newDelegateQueue;
1264
        };
1265
 
1266
        if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) {
1267
                block();
1268
        }
1269
        else {
1270
                if (synchronously)
1271
                        dispatch_sync(socketQueue, block);
1272
                else
1273
                        dispatch_async(socketQueue, block);
1274
        }
1275
}
1276
 
1277
- (void)setDelegate:(id<GCDAsyncSocketDelegate>)newDelegate delegateQueue:(dispatch_queue_t)newDelegateQueue
1278
{
1279
        [self setDelegate:newDelegate delegateQueue:newDelegateQueue synchronously:NO];
1280
}
1281
 
1282
- (void)synchronouslySetDelegate:(id<GCDAsyncSocketDelegate>)newDelegate delegateQueue:(dispatch_queue_t)newDelegateQueue
1283
{
1284
        [self setDelegate:newDelegate delegateQueue:newDelegateQueue synchronously:YES];
1285
}
1286
 
1287
- (BOOL)isIPv4Enabled
1288
{
1289
        // Note: YES means kIPv4Disabled is OFF
1290
 
1291
        if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
1292
        {
1293
                return ((config & kIPv4Disabled) == 0);
1294
        }
1295
        else
1296
        {
1297
                __block BOOL result;
1298
 
1299
                dispatch_sync(socketQueue, ^{
1300
            result = ((self->config & kIPv4Disabled) == 0);
1301
                });
1302
 
1303
                return result;
1304
        }
1305
}
1306
 
1307
- (void)setIPv4Enabled:(BOOL)flag
1308
{
1309
        // Note: YES means kIPv4Disabled is OFF
1310
 
1311
        dispatch_block_t block = ^{
1312
 
1313
                if (flag)
1314
            self->config &= ~kIPv4Disabled;
1315
                else
1316
            self->config |= kIPv4Disabled;
1317
        };
1318
 
1319
        if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
1320
                block();
1321
        else
1322
                dispatch_async(socketQueue, block);
1323
}
1324
 
1325
- (BOOL)isIPv6Enabled
1326
{
1327
        // Note: YES means kIPv6Disabled is OFF
1328
 
1329
        if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
1330
        {
1331
                return ((config & kIPv6Disabled) == 0);
1332
        }
1333
        else
1334
        {
1335
                __block BOOL result;
1336
 
1337
                dispatch_sync(socketQueue, ^{
1338
            result = ((self->config & kIPv6Disabled) == 0);
1339
                });
1340
 
1341
                return result;
1342
        }
1343
}
1344
 
1345
- (void)setIPv6Enabled:(BOOL)flag
1346
{
1347
        // Note: YES means kIPv6Disabled is OFF
1348
 
1349
        dispatch_block_t block = ^{
1350
 
1351
                if (flag)
1352
            self->config &= ~kIPv6Disabled;
1353
                else
1354
            self->config |= kIPv6Disabled;
1355
        };
1356
 
1357
        if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
1358
                block();
1359
        else
1360
                dispatch_async(socketQueue, block);
1361
}
1362
 
1363
- (BOOL)isIPv4PreferredOverIPv6
1364
{
1365
        // Note: YES means kPreferIPv6 is OFF
1366
 
1367
        if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
1368
        {
1369
                return ((config & kPreferIPv6) == 0);
1370
        }
1371
        else
1372
        {
1373
                __block BOOL result;
1374
 
1375
                dispatch_sync(socketQueue, ^{
1376
            result = ((self->config & kPreferIPv6) == 0);
1377
                });
1378
 
1379
                return result;
1380
        }
1381
}
1382
 
1383
- (void)setIPv4PreferredOverIPv6:(BOOL)flag
1384
{
1385
        // Note: YES means kPreferIPv6 is OFF
1386
 
1387
        dispatch_block_t block = ^{
1388
 
1389
                if (flag)
1390
            self->config &= ~kPreferIPv6;
1391
                else
1392
            self->config |= kPreferIPv6;
1393
        };
1394
 
1395
        if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
1396
                block();
1397
        else
1398
                dispatch_async(socketQueue, block);
1399
}
1400
 
1401
- (NSTimeInterval) alternateAddressDelay {
1402
    __block NSTimeInterval delay;
1403
    dispatch_block_t block = ^{
1404
        delay = self->alternateAddressDelay;
1405
    };
1406
    if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
1407
        block();
1408
    else
1409
        dispatch_sync(socketQueue, block);
1410
    return delay;
1411
}
1412
 
1413
- (void) setAlternateAddressDelay:(NSTimeInterval)delay {
1414
    dispatch_block_t block = ^{
1415
        self->alternateAddressDelay = delay;
1416
    };
1417
    if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
1418
        block();
1419
    else
1420
        dispatch_async(socketQueue, block);
1421
}
1422
 
1423
- (id)userData
1424
{
1425
        __block id result = nil;
1426
 
1427
        dispatch_block_t block = ^{
1428
 
1429
        result = self->userData;
1430
        };
1431
 
1432
        if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
1433
                block();
1434
        else
1435
                dispatch_sync(socketQueue, block);
1436
 
1437
        return result;
1438
}
1439
 
1440
- (void)setUserData:(id)arbitraryUserData
1441
{
1442
        dispatch_block_t block = ^{
1443
 
1444
        if (self->userData != arbitraryUserData)
1445
                {
1446
            self->userData = arbitraryUserData;
1447
                }
1448
        };
1449
 
1450
        if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
1451
                block();
1452
        else
1453
                dispatch_async(socketQueue, block);
1454
}
1455
 
1456
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1457
#pragma mark Accepting
1458
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1459
 
1460
- (BOOL)acceptOnPort:(uint16_t)port error:(NSError **)errPtr
1461
{
1462
        return [self acceptOnInterface:nil port:port error:errPtr];
1463
}
1464
 
1465
- (BOOL)acceptOnInterface:(NSString *)inInterface port:(uint16_t)port error:(NSError **)errPtr
1466
{
1467
        LogTrace();
1468
 
1469
        // Just in-case interface parameter is immutable.
1470
        NSString *interface = [inInterface copy];
1471
 
1472
        __block BOOL result = NO;
1473
        __block NSError *err = nil;
1474
 
1475
        // CreateSocket Block
1476
        // This block will be invoked within the dispatch block below.
1477
 
1478
        int(^createSocket)(int, NSData*) = ^int (int domain, NSData *interfaceAddr) {
1479
 
1480
                int socketFD = socket(domain, SOCK_STREAM, 0);
1481
 
1482
                if (socketFD == SOCKET_NULL)
1483
                {
1484
                        NSString *reason = @"Error in socket() function";
1485
                        err = [self errorWithErrno:errno reason:reason];
1486
 
1487
                        return SOCKET_NULL;
1488
                }
1489
 
1490
                int status;
1491
 
1492
                // Set socket options
1493
 
1494
                status = fcntl(socketFD, F_SETFL, O_NONBLOCK);
1495
                if (status == -1)
1496
                {
1497
                        NSString *reason = @"Error enabling non-blocking IO on socket (fcntl)";
1498
                        err = [self errorWithErrno:errno reason:reason];
1499
 
1500
                        LogVerbose(@"close(socketFD)");
1501
                        close(socketFD);
1502
                        return SOCKET_NULL;
1503
                }
1504
 
1505
                int reuseOn = 1;
1506
                status = setsockopt(socketFD, SOL_SOCKET, SO_REUSEADDR, &reuseOn, sizeof(reuseOn));
1507
                if (status == -1)
1508
                {
1509
                        NSString *reason = @"Error enabling address reuse (setsockopt)";
1510
                        err = [self errorWithErrno:errno reason:reason];
1511
 
1512
                        LogVerbose(@"close(socketFD)");
1513
                        close(socketFD);
1514
                        return SOCKET_NULL;
1515
                }
1516
 
1517
                // Bind socket
1518
 
1519
                status = bind(socketFD, (const struct sockaddr *)[interfaceAddr bytes], (socklen_t)[interfaceAddr length]);
1520
                if (status == -1)
1521
                {
1522
                        NSString *reason = @"Error in bind() function";
1523
                        err = [self errorWithErrno:errno reason:reason];
1524
 
1525
                        LogVerbose(@"close(socketFD)");
1526
                        close(socketFD);
1527
                        return SOCKET_NULL;
1528
                }
1529
 
1530
                // Listen
1531
 
1532
                status = listen(socketFD, 1024);
1533
                if (status == -1)
1534
                {
1535
                        NSString *reason = @"Error in listen() function";
1536
                        err = [self errorWithErrno:errno reason:reason];
1537
 
1538
                        LogVerbose(@"close(socketFD)");
1539
                        close(socketFD);
1540
                        return SOCKET_NULL;
1541
                }
1542
 
1543
                return socketFD;
1544
        };
1545
 
1546
        // Create dispatch block and run on socketQueue
1547
 
1548
        dispatch_block_t block = ^{ @autoreleasepool {
1549
 
1550
        if (self->delegate == nil) // Must have delegate set
1551
                {
1552
                        NSString *msg = @"Attempting to accept without a delegate. Set a delegate first.";
1553
                        err = [self badConfigError:msg];
1554
 
1555
                        return_from_block;
1556
                }
1557
 
1558
        if (self->delegateQueue == NULL) // Must have delegate queue set
1559
                {
1560
                        NSString *msg = @"Attempting to accept without a delegate queue. Set a delegate queue first.";
1561
                        err = [self badConfigError:msg];
1562
 
1563
                        return_from_block;
1564
                }
1565
 
1566
        BOOL isIPv4Disabled = (self->config & kIPv4Disabled) ? YES : NO;
1567
        BOOL isIPv6Disabled = (self->config & kIPv6Disabled) ? YES : NO;
1568
 
1569
                if (isIPv4Disabled && isIPv6Disabled) // Must have IPv4 or IPv6 enabled
1570
                {
1571
                        NSString *msg = @"Both IPv4 and IPv6 have been disabled. Must enable at least one protocol first.";
1572
                        err = [self badConfigError:msg];
1573
 
1574
                        return_from_block;
1575
                }
1576
 
1577
                if (![self isDisconnected]) // Must be disconnected
1578
                {
1579
                        NSString *msg = @"Attempting to accept while connected or accepting connections. Disconnect first.";
1580
                        err = [self badConfigError:msg];
1581
 
1582
                        return_from_block;
1583
                }
1584
 
1585
                // Clear queues (spurious read/write requests post disconnect)
1586
        [self->readQueue removeAllObjects];
1587
        [self->writeQueue removeAllObjects];
1588
 
1589
                // Resolve interface from description
1590
 
1591
                NSMutableData *interface4 = nil;
1592
                NSMutableData *interface6 = nil;
1593
 
1594
                [self getInterfaceAddress4:&interface4 address6:&interface6 fromDescription:interface port:port];
1595
 
1596
                if ((interface4 == nil) && (interface6 == nil))
1597
                {
1598
                        NSString *msg = @"Unknown interface. Specify valid interface by name (e.g. \"en1\") or IP address.";
1599
                        err = [self badParamError:msg];
1600
 
1601
                        return_from_block;
1602
                }
1603
 
1604
                if (isIPv4Disabled && (interface6 == nil))
1605
                {
1606
                        NSString *msg = @"IPv4 has been disabled and specified interface doesn't support IPv6.";
1607
                        err = [self badParamError:msg];
1608
 
1609
                        return_from_block;
1610
                }
1611
 
1612
                if (isIPv6Disabled && (interface4 == nil))
1613
                {
1614
                        NSString *msg = @"IPv6 has been disabled and specified interface doesn't support IPv4.";
1615
                        err = [self badParamError:msg];
1616
 
1617
                        return_from_block;
1618
                }
1619
 
1620
                BOOL enableIPv4 = !isIPv4Disabled && (interface4 != nil);
1621
                BOOL enableIPv6 = !isIPv6Disabled && (interface6 != nil);
1622
 
1623
                // Create sockets, configure, bind, and listen
1624
 
1625
                if (enableIPv4)
1626
                {
1627
                        LogVerbose(@"Creating IPv4 socket");
1628
            self->socket4FD = createSocket(AF_INET, interface4);
1629
 
1630
            if (self->socket4FD == SOCKET_NULL)
1631
                        {
1632
                                return_from_block;
1633
                        }
1634
                }
1635
 
1636
                if (enableIPv6)
1637
                {
1638
                        LogVerbose(@"Creating IPv6 socket");
1639
 
1640
                        if (enableIPv4 && (port == 0))
1641
                        {
1642
                                // No specific port was specified, so we allowed the OS to pick an available port for us.
1643
                                // Now we need to make sure the IPv6 socket listens on the same port as the IPv4 socket.
1644
 
1645
                                struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)[interface6 mutableBytes];
1646
                                addr6->sin6_port = htons([self localPort4]);
1647
                        }
1648
 
1649
            self->socket6FD = createSocket(AF_INET6, interface6);
1650
 
1651
            if (self->socket6FD == SOCKET_NULL)
1652
                        {
1653
                if (self->socket4FD != SOCKET_NULL)
1654
                                {
1655
                                        LogVerbose(@"close(socket4FD)");
1656
                    close(self->socket4FD);
1657
                    self->socket4FD = SOCKET_NULL;
1658
                                }
1659
 
1660
                                return_from_block;
1661
                        }
1662
                }
1663
 
1664
                // Create accept sources
1665
 
1666
                if (enableIPv4)
1667
                {
1668
            self->accept4Source = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, self->socket4FD, 0, self->socketQueue);
1669
 
1670
            int socketFD = self->socket4FD;
1671
            dispatch_source_t acceptSource = self->accept4Source;
1672
 
1673
                        __weak GCDAsyncSocket *weakSelf = self;
1674
 
1675
            dispatch_source_set_event_handler(self->accept4Source, ^{ @autoreleasepool {
1676
                        #pragma clang diagnostic push
1677
                        #pragma clang diagnostic warning "-Wimplicit-retain-self"
1678
 
1679
                                __strong GCDAsyncSocket *strongSelf = weakSelf;
1680
                                if (strongSelf == nil) return_from_block;
1681
 
1682
                                LogVerbose(@"event4Block");
1683
 
1684
                                unsigned long i = 0;
1685
                                unsigned long numPendingConnections = dispatch_source_get_data(acceptSource);
1686
 
1687
                                LogVerbose(@"numPendingConnections: %lu", numPendingConnections);
1688
 
1689
                                while ([strongSelf doAccept:socketFD] && (++i < numPendingConnections));
1690
 
1691
                        #pragma clang diagnostic pop
1692
                        }});
1693
 
1694
 
1695
            dispatch_source_set_cancel_handler(self->accept4Source, ^{
1696
                        #pragma clang diagnostic push
1697
                        #pragma clang diagnostic warning "-Wimplicit-retain-self"
1698
 
1699
                                #if !OS_OBJECT_USE_OBJC
1700
                                LogVerbose(@"dispatch_release(accept4Source)");
1701
                                dispatch_release(acceptSource);
1702
                                #endif
1703
 
1704
                                LogVerbose(@"close(socket4FD)");
1705
                                close(socketFD);
1706
 
1707
                        #pragma clang diagnostic pop
1708
                        });
1709
 
1710
                        LogVerbose(@"dispatch_resume(accept4Source)");
1711
            dispatch_resume(self->accept4Source);
1712
                }
1713
 
1714
                if (enableIPv6)
1715
                {
1716
            self->accept6Source = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, self->socket6FD, 0, self->socketQueue);
1717
 
1718
            int socketFD = self->socket6FD;
1719
            dispatch_source_t acceptSource = self->accept6Source;
1720
 
1721
                        __weak GCDAsyncSocket *weakSelf = self;
1722
 
1723
            dispatch_source_set_event_handler(self->accept6Source, ^{ @autoreleasepool {
1724
                        #pragma clang diagnostic push
1725
                        #pragma clang diagnostic warning "-Wimplicit-retain-self"
1726
 
1727
                                __strong GCDAsyncSocket *strongSelf = weakSelf;
1728
                                if (strongSelf == nil) return_from_block;
1729
 
1730
                                LogVerbose(@"event6Block");
1731
 
1732
                                unsigned long i = 0;
1733
                                unsigned long numPendingConnections = dispatch_source_get_data(acceptSource);
1734
 
1735
                                LogVerbose(@"numPendingConnections: %lu", numPendingConnections);
1736
 
1737
                                while ([strongSelf doAccept:socketFD] && (++i < numPendingConnections));
1738
 
1739
                        #pragma clang diagnostic pop
1740
                        }});
1741
 
1742
            dispatch_source_set_cancel_handler(self->accept6Source, ^{
1743
                        #pragma clang diagnostic push
1744
                        #pragma clang diagnostic warning "-Wimplicit-retain-self"
1745
 
1746
                                #if !OS_OBJECT_USE_OBJC
1747
                                LogVerbose(@"dispatch_release(accept6Source)");
1748
                                dispatch_release(acceptSource);
1749
                                #endif
1750
 
1751
                                LogVerbose(@"close(socket6FD)");
1752
                                close(socketFD);
1753
 
1754
                        #pragma clang diagnostic pop
1755
                        });
1756
 
1757
                        LogVerbose(@"dispatch_resume(accept6Source)");
1758
            dispatch_resume(self->accept6Source);
1759
                }
1760
 
1761
        self->flags |= kSocketStarted;
1762
 
1763
                result = YES;
1764
        }};
1765
 
1766
        if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
1767
                block();
1768
        else
1769
                dispatch_sync(socketQueue, block);
1770
 
1771
        if (result == NO)
1772
        {
1773
                LogInfo(@"Error in accept: %@", err);
1774
 
1775
                if (errPtr)
1776
                        *errPtr = err;
1777
        }
1778
 
1779
        return result;
1780
}
1781
 
1782
- (BOOL)acceptOnUrl:(NSURL *)url error:(NSError **)errPtr
1783
{
1784
        LogTrace();
1785
 
1786
        __block BOOL result = NO;
1787
        __block NSError *err = nil;
1788
 
1789
        // CreateSocket Block
1790
        // This block will be invoked within the dispatch block below.
1791
 
1792
        int(^createSocket)(int, NSData*) = ^int (int domain, NSData *interfaceAddr) {
1793
 
1794
                int socketFD = socket(domain, SOCK_STREAM, 0);
1795
 
1796
                if (socketFD == SOCKET_NULL)
1797
                {
1798
                        NSString *reason = @"Error in socket() function";
1799
                        err = [self errorWithErrno:errno reason:reason];
1800
 
1801
                        return SOCKET_NULL;
1802
                }
1803
 
1804
                int status;
1805
 
1806
                // Set socket options
1807
 
1808
                status = fcntl(socketFD, F_SETFL, O_NONBLOCK);
1809
                if (status == -1)
1810
                {
1811
                        NSString *reason = @"Error enabling non-blocking IO on socket (fcntl)";
1812
                        err = [self errorWithErrno:errno reason:reason];
1813
 
1814
                        LogVerbose(@"close(socketFD)");
1815
                        close(socketFD);
1816
                        return SOCKET_NULL;
1817
                }
1818
 
1819
                int reuseOn = 1;
1820
                status = setsockopt(socketFD, SOL_SOCKET, SO_REUSEADDR, &reuseOn, sizeof(reuseOn));
1821
                if (status == -1)
1822
                {
1823
                        NSString *reason = @"Error enabling address reuse (setsockopt)";
1824
                        err = [self errorWithErrno:errno reason:reason];
1825
 
1826
                        LogVerbose(@"close(socketFD)");
1827
                        close(socketFD);
1828
                        return SOCKET_NULL;
1829
                }
1830
 
1831
                // Bind socket
1832
 
1833
                status = bind(socketFD, (const struct sockaddr *)[interfaceAddr bytes], (socklen_t)[interfaceAddr length]);
1834
                if (status == -1)
1835
                {
1836
                        NSString *reason = @"Error in bind() function";
1837
                        err = [self errorWithErrno:errno reason:reason];
1838
 
1839
                        LogVerbose(@"close(socketFD)");
1840
                        close(socketFD);
1841
                        return SOCKET_NULL;
1842
                }
1843
 
1844
                // Listen
1845
 
1846
                status = listen(socketFD, 1024);
1847
                if (status == -1)
1848
                {
1849
                        NSString *reason = @"Error in listen() function";
1850
                        err = [self errorWithErrno:errno reason:reason];
1851
 
1852
                        LogVerbose(@"close(socketFD)");
1853
                        close(socketFD);
1854
                        return SOCKET_NULL;
1855
                }
1856
 
1857
                return socketFD;
1858
        };
1859
 
1860
        // Create dispatch block and run on socketQueue
1861
 
1862
        dispatch_block_t block = ^{ @autoreleasepool {
1863
 
1864
        if (self->delegate == nil) // Must have delegate set
1865
                {
1866
                        NSString *msg = @"Attempting to accept without a delegate. Set a delegate first.";
1867
                        err = [self badConfigError:msg];
1868
 
1869
                        return_from_block;
1870
                }
1871
 
1872
        if (self->delegateQueue == NULL) // Must have delegate queue set
1873
                {
1874
                        NSString *msg = @"Attempting to accept without a delegate queue. Set a delegate queue first.";
1875
                        err = [self badConfigError:msg];
1876
 
1877
                        return_from_block;
1878
                }
1879
 
1880
                if (![self isDisconnected]) // Must be disconnected
1881
                {
1882
                        NSString *msg = @"Attempting to accept while connected or accepting connections. Disconnect first.";
1883
                        err = [self badConfigError:msg];
1884
 
1885
                        return_from_block;
1886
                }
1887
 
1888
                // Clear queues (spurious read/write requests post disconnect)
1889
        [self->readQueue removeAllObjects];
1890
        [self->writeQueue removeAllObjects];
1891
 
1892
                // Remove a previous socket
1893
 
1894
                NSError *error = nil;
1895
                NSFileManager *fileManager = [NSFileManager defaultManager];
1896
                NSString *urlPath = url.path;
1897
                if (urlPath && [fileManager fileExistsAtPath:urlPath]) {
1898
                        if (![fileManager removeItemAtURL:url error:&error]) {
1899
                                NSString *msg = @"Could not remove previous unix domain socket at given url.";
1900
                                err = [self otherError:msg];
1901
 
1902
                                return_from_block;
1903
                        }
1904
                }
1905
 
1906
                // Resolve interface from description
1907
 
1908
                NSData *interface = [self getInterfaceAddressFromUrl:url];
1909
 
1910
                if (interface == nil)
1911
                {
1912
                        NSString *msg = @"Invalid unix domain url. Specify a valid file url that does not exist (e.g. \"file:///tmp/socket\")";
1913
                        err = [self badParamError:msg];
1914
 
1915
                        return_from_block;
1916
                }
1917
 
1918
                // Create sockets, configure, bind, and listen
1919
 
1920
                LogVerbose(@"Creating unix domain socket");
1921
        self->socketUN = createSocket(AF_UNIX, interface);
1922
 
1923
        if (self->socketUN == SOCKET_NULL)
1924
                {
1925
                        return_from_block;
1926
                }
1927
 
1928
        self->socketUrl = url;
1929
 
1930
                // Create accept sources
1931
 
1932
        self->acceptUNSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, self->socketUN, 0, self->socketQueue);
1933
 
1934
        int socketFD = self->socketUN;
1935
        dispatch_source_t acceptSource = self->acceptUNSource;
1936
 
1937
                __weak GCDAsyncSocket *weakSelf = self;
1938
 
1939
        dispatch_source_set_event_handler(self->acceptUNSource, ^{ @autoreleasepool {
1940
 
1941
                        __strong GCDAsyncSocket *strongSelf = weakSelf;
1942
 
1943
                        LogVerbose(@"eventUNBlock");
1944
 
1945
                        unsigned long i = 0;
1946
                        unsigned long numPendingConnections = dispatch_source_get_data(acceptSource);
1947
 
1948
                        LogVerbose(@"numPendingConnections: %lu", numPendingConnections);
1949
 
1950
                        while ([strongSelf doAccept:socketFD] && (++i < numPendingConnections));
1951
                }});
1952
 
1953
        dispatch_source_set_cancel_handler(self->acceptUNSource, ^{
1954
 
1955
#if !OS_OBJECT_USE_OBJC
1956
                        LogVerbose(@"dispatch_release(acceptUNSource)");
1957
                        dispatch_release(acceptSource);
1958
#endif
1959
 
1960
                        LogVerbose(@"close(socketUN)");
1961
                        close(socketFD);
1962
                });
1963
 
1964
                LogVerbose(@"dispatch_resume(acceptUNSource)");
1965
        dispatch_resume(self->acceptUNSource);
1966
 
1967
        self->flags |= kSocketStarted;
1968
 
1969
                result = YES;
1970
        }};
1971
 
1972
        if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
1973
                block();
1974
        else
1975
                dispatch_sync(socketQueue, block);
1976
 
1977
        if (result == NO)
1978
        {
1979
                LogInfo(@"Error in accept: %@", err);
1980
 
1981
                if (errPtr)
1982
                        *errPtr = err;
1983
        }
1984
 
1985
        return result; 
1986
}
1987
 
1988
- (BOOL)doAccept:(int)parentSocketFD
1989
{
1990
        LogTrace();
1991
 
1992
        int socketType;
1993
        int childSocketFD;
1994
        NSData *childSocketAddress;
1995
 
1996
        if (parentSocketFD == socket4FD)
1997
        {
1998
                socketType = 0;
1999
 
2000
                struct sockaddr_in addr;
2001
                socklen_t addrLen = sizeof(addr);
2002
 
2003
                childSocketFD = accept(parentSocketFD, (struct sockaddr *)&addr, &addrLen);
2004
 
2005
                if (childSocketFD == -1)
2006
                {
2007
                        LogWarn(@"Accept failed with error: %@", [self errnoError]);
2008
                        return NO;
2009
                }
2010
 
2011
                childSocketAddress = [NSData dataWithBytes:&addr length:addrLen];
2012
        }
2013
        else if (parentSocketFD == socket6FD)
2014
        {
2015
                socketType = 1;
2016
 
2017
                struct sockaddr_in6 addr;
2018
                socklen_t addrLen = sizeof(addr);
2019
 
2020
                childSocketFD = accept(parentSocketFD, (struct sockaddr *)&addr, &addrLen);
2021
 
2022
                if (childSocketFD == -1)
2023
                {
2024
                        LogWarn(@"Accept failed with error: %@", [self errnoError]);
2025
                        return NO;
2026
                }
2027
 
2028
                childSocketAddress = [NSData dataWithBytes:&addr length:addrLen];
2029
        }
2030
        else // if (parentSocketFD == socketUN)
2031
        {
2032
                socketType = 2;
2033
 
2034
                struct sockaddr_un addr;
2035
                socklen_t addrLen = sizeof(addr);
2036
 
2037
                childSocketFD = accept(parentSocketFD, (struct sockaddr *)&addr, &addrLen);
2038
 
2039
                if (childSocketFD == -1)
2040
                {
2041
                        LogWarn(@"Accept failed with error: %@", [self errnoError]);
2042
                        return NO;
2043
                }
2044
 
2045
                childSocketAddress = [NSData dataWithBytes:&addr length:addrLen];
2046
        }
2047
 
2048
        // Enable non-blocking IO on the socket
2049
 
2050
        int result = fcntl(childSocketFD, F_SETFL, O_NONBLOCK);
2051
        if (result == -1)
2052
        {
2053
                LogWarn(@"Error enabling non-blocking IO on accepted socket (fcntl)");
2054
                LogVerbose(@"close(childSocketFD)");
2055
                close(childSocketFD);
2056
                return NO;
2057
        }
2058
 
2059
        // Prevent SIGPIPE signals
2060
 
2061
        int nosigpipe = 1;
2062
        setsockopt(childSocketFD, SOL_SOCKET, SO_NOSIGPIPE, &nosigpipe, sizeof(nosigpipe));
2063
 
2064
        // Notify delegate
2065
 
2066
        if (delegateQueue)
2067
        {
2068
                __strong id<GCDAsyncSocketDelegate> theDelegate = delegate;
2069
 
2070
                dispatch_async(delegateQueue, ^{ @autoreleasepool {
2071
 
2072
                        // Query delegate for custom socket queue
2073
 
2074
                        dispatch_queue_t childSocketQueue = NULL;
2075
 
2076
                        if ([theDelegate respondsToSelector:@selector(newSocketQueueForConnectionFromAddress:onSocket:)])
2077
                        {
2078
                                childSocketQueue = [theDelegate newSocketQueueForConnectionFromAddress:childSocketAddress
2079
                                                                                              onSocket:self];
2080
                        }
2081
 
2082
                        // Create GCDAsyncSocket instance for accepted socket
2083
 
2084
                        GCDAsyncSocket *acceptedSocket = [[[self class] alloc] initWithDelegate:theDelegate
2085
                                                                      delegateQueue:self->delegateQueue
2086
                                                                                                                                                socketQueue:childSocketQueue];
2087
 
2088
                        if (socketType == 0)
2089
                                acceptedSocket->socket4FD = childSocketFD;
2090
                        else if (socketType == 1)
2091
                                acceptedSocket->socket6FD = childSocketFD;
2092
                        else
2093
                                acceptedSocket->socketUN = childSocketFD;
2094
 
2095
                        acceptedSocket->flags = (kSocketStarted | kConnected);
2096
 
2097
                        // Setup read and write sources for accepted socket
2098
 
2099
                        dispatch_async(acceptedSocket->socketQueue, ^{ @autoreleasepool {
2100
 
2101
                                [acceptedSocket setupReadAndWriteSourcesForNewlyConnectedSocket:childSocketFD];
2102
                        }});
2103
 
2104
                        // Notify delegate
2105
 
2106
                        if ([theDelegate respondsToSelector:@selector(socket:didAcceptNewSocket:)])
2107
                        {
2108
                                [theDelegate socket:self didAcceptNewSocket:acceptedSocket];
2109
                        }
2110
 
2111
                        // Release the socket queue returned from the delegate (it was retained by acceptedSocket)
2112
                        #if !OS_OBJECT_USE_OBJC
2113
                        if (childSocketQueue) dispatch_release(childSocketQueue);
2114
                        #endif
2115
 
2116
                        // The accepted socket should have been retained by the delegate.
2117
                        // Otherwise it gets properly released when exiting the block.
2118
                }});
2119
        }
2120
 
2121
        return YES;
2122
}
2123
 
2124
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2125
#pragma mark Connecting
2126
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2127
 
2128
/**
2129
 * This method runs through the various checks required prior to a connection attempt.
2130
 * It is shared between the connectToHost and connectToAddress methods.
2131
 *
2132
**/
2133
- (BOOL)preConnectWithInterface:(NSString *)interface error:(NSError **)errPtr
2134
{
2135
        NSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @"Must be dispatched on socketQueue");
2136
 
2137
        if (delegate == nil) // Must have delegate set
2138
        {
2139
                if (errPtr)
2140
                {
2141
                        NSString *msg = @"Attempting to connect without a delegate. Set a delegate first.";
2142
                        *errPtr = [self badConfigError:msg];
2143
                }
2144
                return NO;
2145
        }
2146
 
2147
        if (delegateQueue == NULL) // Must have delegate queue set
2148
        {
2149
                if (errPtr)
2150
                {
2151
                        NSString *msg = @"Attempting to connect without a delegate queue. Set a delegate queue first.";
2152
                        *errPtr = [self badConfigError:msg];
2153
                }
2154
                return NO;
2155
        }
2156
 
2157
        if (![self isDisconnected]) // Must be disconnected
2158
        {
2159
                if (errPtr)
2160
                {
2161
                        NSString *msg = @"Attempting to connect while connected or accepting connections. Disconnect first.";
2162
                        *errPtr = [self badConfigError:msg];
2163
                }
2164
                return NO;
2165
        }
2166
 
2167
        BOOL isIPv4Disabled = (config & kIPv4Disabled) ? YES : NO;
2168
        BOOL isIPv6Disabled = (config & kIPv6Disabled) ? YES : NO;
2169
 
2170
        if (isIPv4Disabled && isIPv6Disabled) // Must have IPv4 or IPv6 enabled
2171
        {
2172
                if (errPtr)
2173
                {
2174
                        NSString *msg = @"Both IPv4 and IPv6 have been disabled. Must enable at least one protocol first.";
2175
                        *errPtr = [self badConfigError:msg];
2176
                }
2177
                return NO;
2178
        }
2179
 
2180
        if (interface)
2181
        {
2182
                NSMutableData *interface4 = nil;
2183
                NSMutableData *interface6 = nil;
2184
 
2185
                [self getInterfaceAddress4:&interface4 address6:&interface6 fromDescription:interface port:0];
2186
 
2187
                if ((interface4 == nil) && (interface6 == nil))
2188
                {
2189
                        if (errPtr)
2190
                        {
2191
                                NSString *msg = @"Unknown interface. Specify valid interface by name (e.g. \"en1\") or IP address.";
2192
                                *errPtr = [self badParamError:msg];
2193
                        }
2194
                        return NO;
2195
                }
2196
 
2197
                if (isIPv4Disabled && (interface6 == nil))
2198
                {
2199
                        if (errPtr)
2200
                        {
2201
                                NSString *msg = @"IPv4 has been disabled and specified interface doesn't support IPv6.";
2202
                                *errPtr = [self badParamError:msg];
2203
                        }
2204
                        return NO;
2205
                }
2206
 
2207
                if (isIPv6Disabled && (interface4 == nil))
2208
                {
2209
                        if (errPtr)
2210
                        {
2211
                                NSString *msg = @"IPv6 has been disabled and specified interface doesn't support IPv4.";
2212
                                *errPtr = [self badParamError:msg];
2213
                        }
2214
                        return NO;
2215
                }
2216
 
2217
                connectInterface4 = interface4;
2218
                connectInterface6 = interface6;
2219
        }
2220
 
2221
        // Clear queues (spurious read/write requests post disconnect)
2222
        [readQueue removeAllObjects];
2223
        [writeQueue removeAllObjects];
2224
 
2225
        return YES;
2226
}
2227
 
2228
- (BOOL)preConnectWithUrl:(NSURL *)url error:(NSError **)errPtr
2229
{
2230
        NSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @"Must be dispatched on socketQueue");
2231
 
2232
        if (delegate == nil) // Must have delegate set
2233
        {
2234
                if (errPtr)
2235
                {
2236
                        NSString *msg = @"Attempting to connect without a delegate. Set a delegate first.";
2237
                        *errPtr = [self badConfigError:msg];
2238
                }
2239
                return NO;
2240
        }
2241
 
2242
        if (delegateQueue == NULL) // Must have delegate queue set
2243
        {
2244
                if (errPtr)
2245
                {
2246
                        NSString *msg = @"Attempting to connect without a delegate queue. Set a delegate queue first.";
2247
                        *errPtr = [self badConfigError:msg];
2248
                }
2249
                return NO;
2250
        }
2251
 
2252
        if (![self isDisconnected]) // Must be disconnected
2253
        {
2254
                if (errPtr)
2255
                {
2256
                        NSString *msg = @"Attempting to connect while connected or accepting connections. Disconnect first.";
2257
                        *errPtr = [self badConfigError:msg];
2258
                }
2259
                return NO;
2260
        }
2261
 
2262
        NSData *interface = [self getInterfaceAddressFromUrl:url];
2263
 
2264
        if (interface == nil)
2265
        {
2266
                if (errPtr)
2267
                {
2268
                        NSString *msg = @"Unknown interface. Specify valid interface by name (e.g. \"en1\") or IP address.";
2269
                        *errPtr = [self badParamError:msg];
2270
                }
2271
                return NO;
2272
        }
2273
 
2274
        connectInterfaceUN = interface;
2275
 
2276
        // Clear queues (spurious read/write requests post disconnect)
2277
        [readQueue removeAllObjects];
2278
        [writeQueue removeAllObjects];
2279
 
2280
        return YES;
2281
}
2282
 
2283
- (BOOL)connectToHost:(NSString*)host onPort:(uint16_t)port error:(NSError **)errPtr
2284
{
2285
        return [self connectToHost:host onPort:port withTimeout:-1 error:errPtr];
2286
}
2287
 
2288
- (BOOL)connectToHost:(NSString *)host
2289
               onPort:(uint16_t)port
2290
          withTimeout:(NSTimeInterval)timeout
2291
                error:(NSError **)errPtr
2292
{
2293
        return [self connectToHost:host onPort:port viaInterface:nil withTimeout:timeout error:errPtr];
2294
}
2295
 
2296
- (BOOL)connectToHost:(NSString *)inHost
2297
               onPort:(uint16_t)port
2298
         viaInterface:(NSString *)inInterface
2299
          withTimeout:(NSTimeInterval)timeout
2300
                error:(NSError **)errPtr
2301
{
2302
        LogTrace();
2303
 
2304
        // Just in case immutable objects were passed
2305
        NSString *host = [inHost copy];
2306
        NSString *interface = [inInterface copy];
2307
 
2308
        __block BOOL result = NO;
2309
        __block NSError *preConnectErr = nil;
2310
 
2311
        dispatch_block_t block = ^{ @autoreleasepool {
2312
 
2313
                // Check for problems with host parameter
2314
 
2315
                if ([host length] == 0)
2316
                {
2317
                        NSString *msg = @"Invalid host parameter (nil or \"\"). Should be a domain name or IP address string.";
2318
                        preConnectErr = [self badParamError:msg];
2319
 
2320
                        return_from_block;
2321
                }
2322
 
2323
                // Run through standard pre-connect checks
2324
 
2325
                if (![self preConnectWithInterface:interface error:&preConnectErr])
2326
                {
2327
                        return_from_block;
2328
                }
2329
 
2330
                // We've made it past all the checks.
2331
                // It's time to start the connection process.
2332
 
2333
        self->flags |= kSocketStarted;
2334
 
2335
                LogVerbose(@"Dispatching DNS lookup...");
2336
 
2337
                // It's possible that the given host parameter is actually a NSMutableString.
2338
                // So we want to copy it now, within this block that will be executed synchronously.
2339
                // This way the asynchronous lookup block below doesn't have to worry about it changing.
2340
 
2341
                NSString *hostCpy = [host copy];
2342
 
2343
        int aStateIndex = self->stateIndex;
2344
                __weak GCDAsyncSocket *weakSelf = self;
2345
 
2346
                dispatch_queue_t globalConcurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
2347
                dispatch_async(globalConcurrentQueue, ^{ @autoreleasepool {
2348
                #pragma clang diagnostic push
2349
                #pragma clang diagnostic warning "-Wimplicit-retain-self"
2350
 
2351
                        NSError *lookupErr = nil;
2352
                        NSMutableArray *addresses = [[self class] lookupHost:hostCpy port:port error:&lookupErr];
2353
 
2354
                        __strong GCDAsyncSocket *strongSelf = weakSelf;
2355
                        if (strongSelf == nil) return_from_block;
2356
 
2357
                        if (lookupErr)
2358
                        {
2359
                                dispatch_async(strongSelf->socketQueue, ^{ @autoreleasepool {
2360
 
2361
                                        [strongSelf lookup:aStateIndex didFail:lookupErr];
2362
                                }});
2363
                        }
2364
                        else
2365
                        {
2366
                                NSData *address4 = nil;
2367
                                NSData *address6 = nil;
2368
 
2369
                                for (NSData *address in addresses)
2370
                                {
2371
                                        if (!address4 && [[self class] isIPv4Address:address])
2372
                                        {
2373
                                                address4 = address;
2374
                                        }
2375
                                        else if (!address6 && [[self class] isIPv6Address:address])
2376
                                        {
2377
                                                address6 = address;
2378
                                        }
2379
                                }
2380
 
2381
                                dispatch_async(strongSelf->socketQueue, ^{ @autoreleasepool {
2382
 
2383
                                        [strongSelf lookup:aStateIndex didSucceedWithAddress4:address4 address6:address6];
2384
                                }});
2385
                        }
2386
 
2387
                #pragma clang diagnostic pop
2388
                }});
2389
 
2390
                [self startConnectTimeout:timeout];
2391
 
2392
                result = YES;
2393
        }};
2394
 
2395
        if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
2396
                block();
2397
        else
2398
                dispatch_sync(socketQueue, block);
2399
 
2400
 
2401
        if (errPtr) *errPtr = preConnectErr;
2402
        return result;
2403
}
2404
 
2405
- (BOOL)connectToAddress:(NSData *)remoteAddr error:(NSError **)errPtr
2406
{
2407
        return [self connectToAddress:remoteAddr viaInterface:nil withTimeout:-1 error:errPtr];
2408
}
2409
 
2410
- (BOOL)connectToAddress:(NSData *)remoteAddr withTimeout:(NSTimeInterval)timeout error:(NSError **)errPtr
2411
{
2412
        return [self connectToAddress:remoteAddr viaInterface:nil withTimeout:timeout error:errPtr];
2413
}
2414
 
2415
- (BOOL)connectToAddress:(NSData *)inRemoteAddr
2416
            viaInterface:(NSString *)inInterface
2417
             withTimeout:(NSTimeInterval)timeout
2418
                   error:(NSError **)errPtr
2419
{
2420
        LogTrace();
2421
 
2422
        // Just in case immutable objects were passed
2423
        NSData *remoteAddr = [inRemoteAddr copy];
2424
        NSString *interface = [inInterface copy];
2425
 
2426
        __block BOOL result = NO;
2427
        __block NSError *err = nil;
2428
 
2429
        dispatch_block_t block = ^{ @autoreleasepool {
2430
 
2431
                // Check for problems with remoteAddr parameter
2432
 
2433
                NSData *address4 = nil;
2434
                NSData *address6 = nil;
2435
 
2436
                if ([remoteAddr length] >= sizeof(struct sockaddr))
2437
                {
2438
                        const struct sockaddr *sockaddr = (const struct sockaddr *)[remoteAddr bytes];
2439
 
2440
                        if (sockaddr->sa_family == AF_INET)
2441
                        {
2442
                                if ([remoteAddr length] == sizeof(struct sockaddr_in))
2443
                                {
2444
                                        address4 = remoteAddr;
2445
                                }
2446
                        }
2447
                        else if (sockaddr->sa_family == AF_INET6)
2448
                        {
2449
                                if ([remoteAddr length] == sizeof(struct sockaddr_in6))
2450
                                {
2451
                                        address6 = remoteAddr;
2452
                                }
2453
                        }
2454
                }
2455
 
2456
                if ((address4 == nil) && (address6 == nil))
2457
                {
2458
                        NSString *msg = @"A valid IPv4 or IPv6 address was not given";
2459
                        err = [self badParamError:msg];
2460
 
2461
                        return_from_block;
2462
                }
2463
 
2464
        BOOL isIPv4Disabled = (self->config & kIPv4Disabled) ? YES : NO;
2465
        BOOL isIPv6Disabled = (self->config & kIPv6Disabled) ? YES : NO;
2466
 
2467
                if (isIPv4Disabled && (address4 != nil))
2468
                {
2469
                        NSString *msg = @"IPv4 has been disabled and an IPv4 address was passed.";
2470
                        err = [self badParamError:msg];
2471
 
2472
                        return_from_block;
2473
                }
2474
 
2475
                if (isIPv6Disabled && (address6 != nil))
2476
                {
2477
                        NSString *msg = @"IPv6 has been disabled and an IPv6 address was passed.";
2478
                        err = [self badParamError:msg];
2479
 
2480
                        return_from_block;
2481
                }
2482
 
2483
                // Run through standard pre-connect checks
2484
 
2485
                if (![self preConnectWithInterface:interface error:&err])
2486
                {
2487
                        return_from_block;
2488
                }
2489
 
2490
                // We've made it past all the checks.
2491
                // It's time to start the connection process.
2492
 
2493
                if (![self connectWithAddress4:address4 address6:address6 error:&err])
2494
                {
2495
                        return_from_block;
2496
                }
2497
 
2498
        self->flags |= kSocketStarted;
2499
 
2500
                [self startConnectTimeout:timeout];
2501
 
2502
                result = YES;
2503
        }};
2504
 
2505
        if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
2506
                block();
2507
        else
2508
                dispatch_sync(socketQueue, block);
2509
 
2510
        if (result == NO)
2511
        {
2512
                if (errPtr)
2513
                        *errPtr = err;
2514
        }
2515
 
2516
        return result;
2517
}
2518
 
2519
- (BOOL)connectToUrl:(NSURL *)url withTimeout:(NSTimeInterval)timeout error:(NSError **)errPtr
2520
{
2521
        LogTrace();
2522
 
2523
        __block BOOL result = NO;
2524
        __block NSError *err = nil;
2525
 
2526
        dispatch_block_t block = ^{ @autoreleasepool {
2527
 
2528
                // Check for problems with host parameter
2529
 
2530
                if ([url.path length] == 0)
2531
                {
2532
                        NSString *msg = @"Invalid unix domain socket url.";
2533
                        err = [self badParamError:msg];
2534
 
2535
                        return_from_block;
2536
                }
2537
 
2538
                // Run through standard pre-connect checks
2539
 
2540
                if (![self preConnectWithUrl:url error:&err])
2541
                {
2542
                        return_from_block;
2543
                }
2544
 
2545
                // We've made it past all the checks.
2546
                // It's time to start the connection process.
2547
 
2548
        self->flags |= kSocketStarted;
2549
 
2550
                // Start the normal connection process
2551
 
2552
                NSError *connectError = nil;
2553
        if (![self connectWithAddressUN:self->connectInterfaceUN error:&connectError])
2554
                {
2555
                        [self closeWithError:connectError];
2556
 
2557
                        return_from_block;
2558
                }
2559
 
2560
                [self startConnectTimeout:timeout];
2561
 
2562
                result = YES;
2563
        }};
2564
 
2565
        if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
2566
                block();
2567
        else
2568
                dispatch_sync(socketQueue, block);
2569
 
2570
        if (result == NO)
2571
        {
2572
                if (errPtr)
2573
                        *errPtr = err;
2574
        }
2575
 
2576
        return result;
2577
}
2578
 
2579
- (BOOL)connectToNetService:(NSNetService *)netService error:(NSError **)errPtr
2580
{
2581
        NSArray* addresses = [netService addresses];
2582
        for (NSData* address in addresses)
2583
        {
2584
                BOOL result = [self connectToAddress:address error:errPtr];
2585
                if (result)
2586
                {
2587
                        return YES;
2588
                }
2589
        }
2590
 
2591
        return NO;
2592
}
2593
 
2594
- (void)lookup:(int)aStateIndex didSucceedWithAddress4:(NSData *)address4 address6:(NSData *)address6
2595
{
2596
        LogTrace();
2597
 
2598
        NSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @"Must be dispatched on socketQueue");
2599
        NSAssert(address4 || address6, @"Expected at least one valid address");
2600
 
2601
        if (aStateIndex != stateIndex)
2602
        {
2603
                LogInfo(@"Ignoring lookupDidSucceed, already disconnected");
2604
 
2605
                // The connect operation has been cancelled.
2606
                // That is, socket was disconnected, or connection has already timed out.
2607
                return;
2608
        }
2609
 
2610
        // Check for problems
2611
 
2612
        BOOL isIPv4Disabled = (config & kIPv4Disabled) ? YES : NO;
2613
        BOOL isIPv6Disabled = (config & kIPv6Disabled) ? YES : NO;
2614
 
2615
        if (isIPv4Disabled && (address6 == nil))
2616
        {
2617
                NSString *msg = @"IPv4 has been disabled and DNS lookup found no IPv6 address.";
2618
 
2619
                [self closeWithError:[self otherError:msg]];
2620
                return;
2621
        }
2622
 
2623
        if (isIPv6Disabled && (address4 == nil))
2624
        {
2625
                NSString *msg = @"IPv6 has been disabled and DNS lookup found no IPv4 address.";
2626
 
2627
                [self closeWithError:[self otherError:msg]];
2628
                return;
2629
        }
2630
 
2631
        // Start the normal connection process
2632
 
2633
        NSError *err = nil;
2634
        if (![self connectWithAddress4:address4 address6:address6 error:&err])
2635
        {
2636
                [self closeWithError:err];
2637
        }
2638
}
2639
 
2640
/**
2641
 * This method is called if the DNS lookup fails.
2642
 * This method is executed on the socketQueue.
2643
 *
2644
 * Since the DNS lookup executed synchronously on a global concurrent queue,
2645
 * the original connection request may have already been cancelled or timed-out by the time this method is invoked.
2646
 * The lookupIndex tells us whether the lookup is still valid or not.
2647
**/
2648
- (void)lookup:(int)aStateIndex didFail:(NSError *)error
2649
{
2650
        LogTrace();
2651
 
2652
        NSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @"Must be dispatched on socketQueue");
2653
 
2654
 
2655
        if (aStateIndex != stateIndex)
2656
        {
2657
                LogInfo(@"Ignoring lookup:didFail: - already disconnected");
2658
 
2659
                // The connect operation has been cancelled.
2660
                // That is, socket was disconnected, or connection has already timed out.
2661
                return;
2662
        }
2663
 
2664
        [self endConnectTimeout];
2665
        [self closeWithError:error];
2666
}
2667
 
2668
- (BOOL)bindSocket:(int)socketFD toInterface:(NSData *)connectInterface error:(NSError **)errPtr
2669
{
2670
    // Bind the socket to the desired interface (if needed)
2671
 
2672
    if (connectInterface)
2673
    {
2674
        LogVerbose(@"Binding socket...");
2675
 
2676
        if ([[self class] portFromAddress:connectInterface] > 0)
2677
        {
2678
            // Since we're going to be binding to a specific port,
2679
            // we should turn on reuseaddr to allow us to override sockets in time_wait.
2680
 
2681
            int reuseOn = 1;
2682
            setsockopt(socketFD, SOL_SOCKET, SO_REUSEADDR, &reuseOn, sizeof(reuseOn));
2683
        }
2684
 
2685
        const struct sockaddr *interfaceAddr = (const struct sockaddr *)[connectInterface bytes];
2686
 
2687
        int result = bind(socketFD, interfaceAddr, (socklen_t)[connectInterface length]);
2688
        if (result != 0)
2689
        {
2690
            if (errPtr)
2691
                *errPtr = [self errorWithErrno:errno reason:@"Error in bind() function"];
2692
 
2693
            return NO;
2694
        }
2695
    }
2696
 
2697
    return YES;
2698
}
2699
 
2700
- (int)createSocket:(int)family connectInterface:(NSData *)connectInterface errPtr:(NSError **)errPtr
2701
{
2702
    int socketFD = socket(family, SOCK_STREAM, 0);
2703
 
2704
    if (socketFD == SOCKET_NULL)
2705
    {
2706
        if (errPtr)
2707
            *errPtr = [self errorWithErrno:errno reason:@"Error in socket() function"];
2708
 
2709
        return socketFD;
2710
    }
2711
 
2712
    if (![self bindSocket:socketFD toInterface:connectInterface error:errPtr])
2713
    {
2714
        [self closeSocket:socketFD];
2715
 
2716
        return SOCKET_NULL;
2717
    }
2718
 
2719
    // Prevent SIGPIPE signals
2720
 
2721
    int nosigpipe = 1;
2722
    setsockopt(socketFD, SOL_SOCKET, SO_NOSIGPIPE, &nosigpipe, sizeof(nosigpipe));
2723
 
2724
    return socketFD;
2725
}
2726
 
2727
- (void)connectSocket:(int)socketFD address:(NSData *)address stateIndex:(int)aStateIndex
2728
{
2729
    // If there already is a socket connected, we close socketFD and return
2730
    if (self.isConnected)
2731
    {
2732
        [self closeSocket:socketFD];
2733
        return;
2734
    }
2735
 
2736
    // Start the connection process in a background queue
2737
 
2738
    __weak GCDAsyncSocket *weakSelf = self;
2739
 
2740
    dispatch_queue_t globalConcurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
2741
    dispatch_async(globalConcurrentQueue, ^{
2742
#pragma clang diagnostic push
2743
#pragma clang diagnostic warning "-Wimplicit-retain-self"
2744
 
2745
        int result = connect(socketFD, (const struct sockaddr *)[address bytes], (socklen_t)[address length]);
2746
        int err = errno;
2747
 
2748
        __strong GCDAsyncSocket *strongSelf = weakSelf;
2749
        if (strongSelf == nil) return_from_block;
2750
 
2751
        dispatch_async(strongSelf->socketQueue, ^{ @autoreleasepool {
2752
 
2753
            if (strongSelf.isConnected)
2754
            {
2755
                [strongSelf closeSocket:socketFD];
2756
                return_from_block;
2757
            }
2758
 
2759
            if (result == 0)
2760
            {
2761
                [self closeUnusedSocket:socketFD];
2762
 
2763
                [strongSelf didConnect:aStateIndex];
2764
            }
2765
            else
2766
            {
2767
                [strongSelf closeSocket:socketFD];
2768
 
2769
                // If there are no more sockets trying to connect, we inform the error to the delegate
2770
                if (strongSelf.socket4FD == SOCKET_NULL && strongSelf.socket6FD == SOCKET_NULL)
2771
                {
2772
                    NSError *error = [strongSelf errorWithErrno:err reason:@"Error in connect() function"];
2773
                    [strongSelf didNotConnect:aStateIndex error:error];
2774
                }
2775
            }
2776
        }});
2777
 
2778
#pragma clang diagnostic pop
2779
    });
2780
 
2781
    LogVerbose(@"Connecting...");
2782
}
2783
 
2784
- (void)closeSocket:(int)socketFD
2785
{
2786
    if (socketFD != SOCKET_NULL &&
2787
        (socketFD == socket6FD || socketFD == socket4FD))
2788
    {
2789
        close(socketFD);
2790
 
2791
        if (socketFD == socket4FD)
2792
        {
2793
            LogVerbose(@"close(socket4FD)");
2794
            socket4FD = SOCKET_NULL;
2795
        }
2796
        else if (socketFD == socket6FD)
2797
        {
2798
            LogVerbose(@"close(socket6FD)");
2799
            socket6FD = SOCKET_NULL;
2800
        }
2801
    }
2802
}
2803
 
2804
- (void)closeUnusedSocket:(int)usedSocketFD
2805
{
2806
    if (usedSocketFD != socket4FD)
2807
    {
2808
        [self closeSocket:socket4FD];
2809
    }
2810
    else if (usedSocketFD != socket6FD)
2811
    {
2812
        [self closeSocket:socket6FD];
2813
    }
2814
}
2815
 
2816
- (BOOL)connectWithAddress4:(NSData *)address4 address6:(NSData *)address6 error:(NSError **)errPtr
2817
{
2818
        LogTrace();
2819
 
2820
        NSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @"Must be dispatched on socketQueue");
2821
 
2822
        LogVerbose(@"IPv4: %@:%hu", [[self class] hostFromAddress:address4], [[self class] portFromAddress:address4]);
2823
        LogVerbose(@"IPv6: %@:%hu", [[self class] hostFromAddress:address6], [[self class] portFromAddress:address6]);
2824
 
2825
        // Determine socket type
2826
 
2827
        BOOL preferIPv6 = (config & kPreferIPv6) ? YES : NO;
2828
 
2829
        // Create and bind the sockets
2830
 
2831
    if (address4)
2832
    {
2833
        LogVerbose(@"Creating IPv4 socket");
2834
 
2835
        socket4FD = [self createSocket:AF_INET connectInterface:connectInterface4 errPtr:errPtr];
2836
    }
2837
 
2838
    if (address6)
2839
    {
2840
        LogVerbose(@"Creating IPv6 socket");
2841
 
2842
        socket6FD = [self createSocket:AF_INET6 connectInterface:connectInterface6 errPtr:errPtr];
2843
    }
2844
 
2845
    if (socket4FD == SOCKET_NULL && socket6FD == SOCKET_NULL)
2846
    {
2847
        return NO;
2848
    }
2849
 
2850
        int socketFD, alternateSocketFD;
2851
        NSData *address, *alternateAddress;
2852
 
2853
    if ((preferIPv6 && socket6FD != SOCKET_NULL) || socket4FD == SOCKET_NULL)
2854
    {
2855
        socketFD = socket6FD;
2856
        alternateSocketFD = socket4FD;
2857
        address = address6;
2858
        alternateAddress = address4;
2859
    }
2860
    else
2861
    {
2862
        socketFD = socket4FD;
2863
        alternateSocketFD = socket6FD;
2864
        address = address4;
2865
        alternateAddress = address6;
2866
    }
2867
 
2868
    int aStateIndex = stateIndex;
2869
 
2870
    [self connectSocket:socketFD address:address stateIndex:aStateIndex];
2871
 
2872
    if (alternateAddress)
2873
    {
2874
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(alternateAddressDelay * NSEC_PER_SEC)), socketQueue, ^{
2875
            [self connectSocket:alternateSocketFD address:alternateAddress stateIndex:aStateIndex];
2876
        });
2877
    }
2878
 
2879
        return YES;
2880
}
2881
 
2882
- (BOOL)connectWithAddressUN:(NSData *)address error:(NSError **)errPtr
2883
{
2884
        LogTrace();
2885
 
2886
        NSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @"Must be dispatched on socketQueue");
2887
 
2888
        // Create the socket
2889
 
2890
        int socketFD;
2891
 
2892
        LogVerbose(@"Creating unix domain socket");
2893
 
2894
        socketUN = socket(AF_UNIX, SOCK_STREAM, 0);
2895
 
2896
        socketFD = socketUN;
2897
 
2898
        if (socketFD == SOCKET_NULL)
2899
        {
2900
                if (errPtr)
2901
                        *errPtr = [self errorWithErrno:errno reason:@"Error in socket() function"];
2902
 
2903
                return NO;
2904
        }
2905
 
2906
        // Bind the socket to the desired interface (if needed)
2907
 
2908
        LogVerbose(@"Binding socket...");
2909
 
2910
        int reuseOn = 1;
2911
        setsockopt(socketFD, SOL_SOCKET, SO_REUSEADDR, &reuseOn, sizeof(reuseOn));
2912
 
2913
//      const struct sockaddr *interfaceAddr = (const struct sockaddr *)[address bytes];
2914
//     
2915
//      int result = bind(socketFD, interfaceAddr, (socklen_t)[address length]);
2916
//      if (result != 0)
2917
//      {
2918
//              if (errPtr)
2919
//                      *errPtr = [self errnoErrorWithReason:@"Error in bind() function"];
2920
//             
2921
//              return NO;
2922
//      }
2923
 
2924
        // Prevent SIGPIPE signals
2925
 
2926
        int nosigpipe = 1;
2927
        setsockopt(socketFD, SOL_SOCKET, SO_NOSIGPIPE, &nosigpipe, sizeof(nosigpipe));
2928
 
2929
        // Start the connection process in a background queue
2930
 
2931
        int aStateIndex = stateIndex;
2932
 
2933
        dispatch_queue_t globalConcurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
2934
        dispatch_async(globalConcurrentQueue, ^{
2935
 
2936
                const struct sockaddr *addr = (const struct sockaddr *)[address bytes];
2937
                int result = connect(socketFD, addr, addr->sa_len);
2938
                if (result == 0)
2939
                {
2940
            dispatch_async(self->socketQueue, ^{ @autoreleasepool {
2941
 
2942
                                [self didConnect:aStateIndex];
2943
                        }});
2944
                }
2945
                else
2946
                {
2947
                        // TODO: Bad file descriptor
2948
                        perror("connect");
2949
                        NSError *error = [self errorWithErrno:errno reason:@"Error in connect() function"];
2950
 
2951
            dispatch_async(self->socketQueue, ^{ @autoreleasepool {
2952
 
2953
                                [self didNotConnect:aStateIndex error:error];
2954
                        }});
2955
                }
2956
        });
2957
 
2958
        LogVerbose(@"Connecting...");
2959
 
2960
        return YES;
2961
}
2962
 
2963
- (void)didConnect:(int)aStateIndex
2964
{
2965
        LogTrace();
2966
 
2967
        NSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @"Must be dispatched on socketQueue");
2968
 
2969
 
2970
        if (aStateIndex != stateIndex)
2971
        {
2972
                LogInfo(@"Ignoring didConnect, already disconnected");
2973
 
2974
                // The connect operation has been cancelled.
2975
                // That is, socket was disconnected, or connection has already timed out.
2976
                return;
2977
        }
2978
 
2979
        flags |= kConnected;
2980
 
2981
        [self endConnectTimeout];
2982
 
2983
        #if TARGET_OS_IPHONE
2984
        // The endConnectTimeout method executed above incremented the stateIndex.
2985
        aStateIndex = stateIndex;
2986
        #endif
2987
 
2988
        // Setup read/write streams (as workaround for specific shortcomings in the iOS platform)
2989
        //
2990
        // Note:
2991
        // There may be configuration options that must be set by the delegate before opening the streams.
2992
        // The primary example is the kCFStreamNetworkServiceTypeVoIP flag, which only works on an unopened stream.
2993
        //
2994
        // Thus we wait until after the socket:didConnectToHost:port: delegate method has completed.
2995
        // This gives the delegate time to properly configure the streams if needed.
2996
 
2997
        dispatch_block_t SetupStreamsPart1 = ^{
2998
                #if TARGET_OS_IPHONE
2999
 
3000
                if (![self createReadAndWriteStream])
3001
                {
3002
                        [self closeWithError:[self otherError:@"Error creating CFStreams"]];
3003
                        return;
3004
                }
3005
 
3006
                if (![self registerForStreamCallbacksIncludingReadWrite:NO])
3007
                {
3008
                        [self closeWithError:[self otherError:@"Error in CFStreamSetClient"]];
3009
                        return;
3010
                }
3011
 
3012
                #endif
3013
        };
3014
        dispatch_block_t SetupStreamsPart2 = ^{
3015
                #if TARGET_OS_IPHONE
3016
 
3017
        if (aStateIndex != self->stateIndex)
3018
                {
3019
                        // The socket has been disconnected.
3020
                        return;
3021
                }
3022
 
3023
                if (![self addStreamsToRunLoop])
3024
                {
3025
                        [self closeWithError:[self otherError:@"Error in CFStreamScheduleWithRunLoop"]];
3026
                        return;
3027
                }
3028
 
3029
                if (![self openStreams])
3030
                {
3031
                        [self closeWithError:[self otherError:@"Error creating CFStreams"]];
3032
                        return;
3033
                }
3034
 
3035
                #endif
3036
        };
3037
 
3038
        // Notify delegate
3039
 
3040
        NSString *host = [self connectedHost];
3041
        uint16_t port = [self connectedPort];
3042
        NSURL *url = [self connectedUrl];
3043
 
3044
        __strong id<GCDAsyncSocketDelegate> theDelegate = delegate;
3045
 
3046
        if (delegateQueue && host != nil && [theDelegate respondsToSelector:@selector(socket:didConnectToHost:port:)])
3047
        {
3048
                SetupStreamsPart1();
3049
 
3050
                dispatch_async(delegateQueue, ^{ @autoreleasepool {
3051
 
3052
                        [theDelegate socket:self didConnectToHost:host port:port];
3053
 
3054
            dispatch_async(self->socketQueue, ^{ @autoreleasepool {
3055
 
3056
                                SetupStreamsPart2();
3057
                        }});
3058
                }});
3059
        }
3060
        else if (delegateQueue && url != nil && [theDelegate respondsToSelector:@selector(socket:didConnectToUrl:)])
3061
        {
3062
                SetupStreamsPart1();
3063
 
3064
                dispatch_async(delegateQueue, ^{ @autoreleasepool {
3065
 
3066
                        [theDelegate socket:self didConnectToUrl:url];
3067
 
3068
            dispatch_async(self->socketQueue, ^{ @autoreleasepool {
3069
 
3070
                                SetupStreamsPart2();
3071
                        }});
3072
                }});
3073
        }
3074
        else
3075
        {
3076
                SetupStreamsPart1();
3077
                SetupStreamsPart2();
3078
        }
3079
 
3080
        // Get the connected socket
3081
 
3082
        int socketFD = (socket4FD != SOCKET_NULL) ? socket4FD : (socket6FD != SOCKET_NULL) ? socket6FD : socketUN;
3083
 
3084
        // Enable non-blocking IO on the socket
3085
 
3086
        int result = fcntl(socketFD, F_SETFL, O_NONBLOCK);
3087
        if (result == -1)
3088
        {
3089
                NSString *errMsg = @"Error enabling non-blocking IO on socket (fcntl)";
3090
                [self closeWithError:[self otherError:errMsg]];
3091
 
3092
                return;
3093
        }
3094
 
3095
        // Setup our read/write sources
3096
 
3097
        [self setupReadAndWriteSourcesForNewlyConnectedSocket:socketFD];
3098
 
3099
        // Dequeue any pending read/write requests
3100
 
3101
        [self maybeDequeueRead];
3102
        [self maybeDequeueWrite];
3103
}
3104
 
3105
- (void)didNotConnect:(int)aStateIndex error:(NSError *)error
3106
{
3107
        LogTrace();
3108
 
3109
        NSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @"Must be dispatched on socketQueue");
3110
 
3111
 
3112
        if (aStateIndex != stateIndex)
3113
        {
3114
                LogInfo(@"Ignoring didNotConnect, already disconnected");
3115
 
3116
                // The connect operation has been cancelled.
3117
                // That is, socket was disconnected, or connection has already timed out.
3118
                return;
3119
        }
3120
 
3121
        [self closeWithError:error];
3122
}
3123
 
3124
- (void)startConnectTimeout:(NSTimeInterval)timeout
3125
{
3126
        if (timeout >= 0.0)
3127
        {
3128
                connectTimer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, socketQueue);
3129
 
3130
                __weak GCDAsyncSocket *weakSelf = self;
3131
 
3132
                dispatch_source_set_event_handler(connectTimer, ^{ @autoreleasepool {
3133
                #pragma clang diagnostic push
3134
                #pragma clang diagnostic warning "-Wimplicit-retain-self"
3135
 
3136
                        __strong GCDAsyncSocket *strongSelf = weakSelf;
3137
                        if (strongSelf == nil) return_from_block;
3138
 
3139
                        [strongSelf doConnectTimeout];
3140
 
3141
                #pragma clang diagnostic pop
3142
                }});
3143
 
3144
                #if !OS_OBJECT_USE_OBJC
3145
                dispatch_source_t theConnectTimer = connectTimer;
3146
                dispatch_source_set_cancel_handler(connectTimer, ^{
3147
                #pragma clang diagnostic push
3148
                #pragma clang diagnostic warning "-Wimplicit-retain-self"
3149
 
3150
                        LogVerbose(@"dispatch_release(connectTimer)");
3151
                        dispatch_release(theConnectTimer);
3152
 
3153
                #pragma clang diagnostic pop
3154
                });
3155
                #endif
3156
 
3157
                dispatch_time_t tt = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(timeout * NSEC_PER_SEC));
3158
                dispatch_source_set_timer(connectTimer, tt, DISPATCH_TIME_FOREVER, 0);
3159
 
3160
                dispatch_resume(connectTimer);
3161
        }
3162
}
3163
 
3164
- (void)endConnectTimeout
3165
{
3166
        LogTrace();
3167
 
3168
        if (connectTimer)
3169
        {
3170
                dispatch_source_cancel(connectTimer);
3171
                connectTimer = NULL;
3172
        }
3173
 
3174
        // Increment stateIndex.
3175
        // This will prevent us from processing results from any related background asynchronous operations.
3176
        //
3177
        // Note: This should be called from close method even if connectTimer is NULL.
3178
        // This is because one might disconnect a socket prior to a successful connection which had no timeout.
3179
 
3180
        stateIndex++;
3181
 
3182
        if (connectInterface4)
3183
        {
3184
                connectInterface4 = nil;
3185
        }
3186
        if (connectInterface6)
3187
        {
3188
                connectInterface6 = nil;
3189
        }
3190
}
3191
 
3192
- (void)doConnectTimeout
3193
{
3194
        LogTrace();
3195
 
3196
        [self endConnectTimeout];
3197
        [self closeWithError:[self connectTimeoutError]];
3198
}
3199
 
3200
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3201
#pragma mark Disconnecting
3202
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3203
 
3204
- (void)closeWithError:(NSError *)error
3205
{
3206
        LogTrace();
3207
        NSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @"Must be dispatched on socketQueue");
3208
 
3209
        [self endConnectTimeout];
3210
 
3211
        if (currentRead != nil)  [self endCurrentRead];
3212
        if (currentWrite != nil) [self endCurrentWrite];
3213
 
3214
        [readQueue removeAllObjects];
3215
        [writeQueue removeAllObjects];
3216
 
3217
        [preBuffer reset];
3218
 
3219
        #if TARGET_OS_IPHONE
3220
        {
3221
                if (readStream || writeStream)
3222
                {
3223
                        [self removeStreamsFromRunLoop];
3224
 
3225
                        if (readStream)
3226
                        {
3227
                                CFReadStreamSetClient(readStream, kCFStreamEventNone, NULL, NULL);
3228
                                CFReadStreamClose(readStream);
3229
                                CFRelease(readStream);
3230
                                readStream = NULL;
3231
                        }
3232
                        if (writeStream)
3233
                        {
3234
                                CFWriteStreamSetClient(writeStream, kCFStreamEventNone, NULL, NULL);
3235
                                CFWriteStreamClose(writeStream);
3236
                                CFRelease(writeStream);
3237
                                writeStream = NULL;
3238
                        }
3239
                }
3240
        }
3241
        #endif
3242
 
3243
        [sslPreBuffer reset];
3244
        sslErrCode = lastSSLHandshakeError = noErr;
3245
 
3246
        if (sslContext)
3247
        {
3248
                // Getting a linker error here about the SSLx() functions?
3249
                // You need to add the Security Framework to your application.
3250
 
3251
                SSLClose(sslContext);
3252
 
3253
                #if TARGET_OS_IPHONE || (__MAC_OS_X_VERSION_MIN_REQUIRED >= 1080)
3254
                CFRelease(sslContext);
3255
                #else
3256
                SSLDisposeContext(sslContext);
3257
                #endif
3258
 
3259
                sslContext = NULL;
3260
        }
3261
 
3262
        // For some crazy reason (in my opinion), cancelling a dispatch source doesn't
3263
        // invoke the cancel handler if the dispatch source is paused.
3264
        // So we have to unpause the source if needed.
3265
        // This allows the cancel handler to be run, which in turn releases the source and closes the socket.
3266
 
3267
        if (!accept4Source && !accept6Source && !acceptUNSource && !readSource && !writeSource)
3268
        {
3269
                LogVerbose(@"manually closing close");
3270
 
3271
                if (socket4FD != SOCKET_NULL)
3272
                {
3273
                        LogVerbose(@"close(socket4FD)");
3274
                        close(socket4FD);
3275
                        socket4FD = SOCKET_NULL;
3276
                }
3277
 
3278
                if (socket6FD != SOCKET_NULL)
3279
                {
3280
                        LogVerbose(@"close(socket6FD)");
3281
                        close(socket6FD);
3282
                        socket6FD = SOCKET_NULL;
3283
                }
3284
 
3285
                if (socketUN != SOCKET_NULL)
3286
                {
3287
                        LogVerbose(@"close(socketUN)");
3288
                        close(socketUN);
3289
                        socketUN = SOCKET_NULL;
3290
                        unlink(socketUrl.path.fileSystemRepresentation);
3291
                        socketUrl = nil;
3292
                }
3293
        }
3294
        else
3295
        {
3296
                if (accept4Source)
3297
                {
3298
                        LogVerbose(@"dispatch_source_cancel(accept4Source)");
3299
                        dispatch_source_cancel(accept4Source);
3300
 
3301
                        // We never suspend accept4Source
3302
 
3303
                        accept4Source = NULL;
3304
                }
3305
 
3306
                if (accept6Source)
3307
                {
3308
                        LogVerbose(@"dispatch_source_cancel(accept6Source)");
3309
                        dispatch_source_cancel(accept6Source);
3310
 
3311
                        // We never suspend accept6Source
3312
 
3313
                        accept6Source = NULL;
3314
                }
3315
 
3316
                if (acceptUNSource)
3317
                {
3318
                        LogVerbose(@"dispatch_source_cancel(acceptUNSource)");
3319
                        dispatch_source_cancel(acceptUNSource);
3320
 
3321
                        // We never suspend acceptUNSource
3322
 
3323
                        acceptUNSource = NULL;
3324
                }
3325
 
3326
                if (readSource)
3327
                {
3328
                        LogVerbose(@"dispatch_source_cancel(readSource)");
3329
                        dispatch_source_cancel(readSource);
3330
 
3331
                        [self resumeReadSource];
3332
 
3333
                        readSource = NULL;
3334
                }
3335
 
3336
                if (writeSource)
3337
                {
3338
                        LogVerbose(@"dispatch_source_cancel(writeSource)");
3339
                        dispatch_source_cancel(writeSource);
3340
 
3341
                        [self resumeWriteSource];
3342
 
3343
                        writeSource = NULL;
3344
                }
3345
 
3346
                // The sockets will be closed by the cancel handlers of the corresponding source
3347
 
3348
                socket4FD = SOCKET_NULL;
3349
                socket6FD = SOCKET_NULL;
3350
                socketUN = SOCKET_NULL;
3351
        }
3352
 
3353
        // If the client has passed the connect/accept method, then the connection has at least begun.
3354
        // Notify delegate that it is now ending.
3355
        BOOL shouldCallDelegate = (flags & kSocketStarted) ? YES : NO;
3356
        BOOL isDeallocating = (flags & kDealloc) ? YES : NO;
3357
 
3358
        // Clear stored socket info and all flags (config remains as is)
3359
        socketFDBytesAvailable = 0;
3360
        flags = 0;
3361
        sslWriteCachedLength = 0;
3362
 
3363
        if (shouldCallDelegate)
3364
        {
3365
                __strong id<GCDAsyncSocketDelegate> theDelegate = delegate;
3366
                __strong id theSelf = isDeallocating ? nil : self;
3367
 
3368
                if (delegateQueue && [theDelegate respondsToSelector: @selector(socketDidDisconnect:withError:)])
3369
                {
3370
                        dispatch_async(delegateQueue, ^{ @autoreleasepool {
3371
 
3372
                                [theDelegate socketDidDisconnect:theSelf withError:error];
3373
                        }});
3374
                }      
3375
        }
3376
}
3377
 
3378
- (void)disconnect
3379
{
3380
        dispatch_block_t block = ^{ @autoreleasepool {
3381
 
3382
        if (self->flags & kSocketStarted)
3383
                {
3384
                        [self closeWithError:nil];
3385
                }
3386
        }};
3387
 
3388
        // Synchronous disconnection, as documented in the header file
3389
 
3390
        if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
3391
                block();
3392
        else
3393
                dispatch_sync(socketQueue, block);
3394
}
3395
 
3396
- (void)disconnectAfterReading
3397
{
3398
        dispatch_async(socketQueue, ^{ @autoreleasepool {
3399
 
3400
        if (self->flags & kSocketStarted)
3401
                {
3402
            self->flags |= (kForbidReadsWrites | kDisconnectAfterReads);
3403
                        [self maybeClose];
3404
                }
3405
        }});
3406
}
3407
 
3408
- (void)disconnectAfterWriting
3409
{
3410
        dispatch_async(socketQueue, ^{ @autoreleasepool {
3411
 
3412
        if (self->flags & kSocketStarted)
3413
                {
3414
            self->flags |= (kForbidReadsWrites | kDisconnectAfterWrites);
3415
                        [self maybeClose];
3416
                }
3417
        }});
3418
}
3419
 
3420
- (void)disconnectAfterReadingAndWriting
3421
{
3422
        dispatch_async(socketQueue, ^{ @autoreleasepool {
3423
 
3424
        if (self->flags & kSocketStarted)
3425
                {
3426
            self->flags |= (kForbidReadsWrites | kDisconnectAfterReads | kDisconnectAfterWrites);
3427
                        [self maybeClose];
3428
                }
3429
        }});
3430
}
3431
 
3432
/**
3433
 * Closes the socket if possible.
3434
 * That is, if all writes have completed, and we're set to disconnect after writing,
3435
 * or if all reads have completed, and we're set to disconnect after reading.
3436
**/
3437
- (void)maybeClose
3438
{
3439
        NSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @"Must be dispatched on socketQueue");
3440
 
3441
        BOOL shouldClose = NO;
3442
 
3443
        if (flags & kDisconnectAfterReads)
3444
        {
3445
                if (([readQueue count] == 0) && (currentRead == nil))
3446
                {
3447
                        if (flags & kDisconnectAfterWrites)
3448
                        {
3449
                                if (([writeQueue count] == 0) && (currentWrite == nil))
3450
                                {
3451
                                        shouldClose = YES;
3452
                                }
3453
                        }
3454
                        else
3455
                        {
3456
                                shouldClose = YES;
3457
                        }
3458
                }
3459
        }
3460
        else if (flags & kDisconnectAfterWrites)
3461
        {
3462
                if (([writeQueue count] == 0) && (currentWrite == nil))
3463
                {
3464
                        shouldClose = YES;
3465
                }
3466
        }
3467
 
3468
        if (shouldClose)
3469
        {
3470
                [self closeWithError:nil];
3471
        }
3472
}
3473
 
3474
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3475
#pragma mark Errors
3476
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3477
 
3478
- (NSError *)badConfigError:(NSString *)errMsg
3479
{
3480
        NSDictionary *userInfo = @{NSLocalizedDescriptionKey : errMsg};
3481
 
3482
        return [NSError errorWithDomain:GCDAsyncSocketErrorDomain code:GCDAsyncSocketBadConfigError userInfo:userInfo];
3483
}
3484
 
3485
- (NSError *)badParamError:(NSString *)errMsg
3486
{
3487
        NSDictionary *userInfo = @{NSLocalizedDescriptionKey : errMsg};
3488
 
3489
        return [NSError errorWithDomain:GCDAsyncSocketErrorDomain code:GCDAsyncSocketBadParamError userInfo:userInfo];
3490
}
3491
 
3492
+ (NSError *)gaiError:(int)gai_error
3493
{
3494
        NSString *errMsg = [NSString stringWithCString:gai_strerror(gai_error) encoding:NSASCIIStringEncoding];
3495
        NSDictionary *userInfo = @{NSLocalizedDescriptionKey : errMsg};
3496
 
3497
        return [NSError errorWithDomain:@"kCFStreamErrorDomainNetDB" code:gai_error userInfo:userInfo];
3498
}
3499
 
3500
- (NSError *)errorWithErrno:(int)err reason:(NSString *)reason
3501
{
3502
        NSString *errMsg = [NSString stringWithUTF8String:strerror(err)];
3503
        NSDictionary *userInfo = @{NSLocalizedDescriptionKey : errMsg,
3504
                                                           NSLocalizedFailureReasonErrorKey : reason};
3505
 
3506
        return [NSError errorWithDomain:NSPOSIXErrorDomain code:err userInfo:userInfo];
3507
}
3508
 
3509
- (NSError *)errnoError
3510
{
3511
        NSString *errMsg = [NSString stringWithUTF8String:strerror(errno)];
3512
        NSDictionary *userInfo = @{NSLocalizedDescriptionKey : errMsg};
3513
 
3514
        return [NSError errorWithDomain:NSPOSIXErrorDomain code:errno userInfo:userInfo];
3515
}
3516
 
3517
- (NSError *)sslError:(OSStatus)ssl_error
3518
{
3519
        NSString *msg = @"Error code definition can be found in Apple's SecureTransport.h";
3520
        NSDictionary *userInfo = @{NSLocalizedRecoverySuggestionErrorKey : msg};
3521
 
3522
        return [NSError errorWithDomain:@"kCFStreamErrorDomainSSL" code:ssl_error userInfo:userInfo];
3523
}
3524
 
3525
- (NSError *)connectTimeoutError
3526
{
3527
        NSString *errMsg = NSLocalizedStringWithDefaultValue(@"GCDAsyncSocketConnectTimeoutError",
3528
                                                             @"GCDAsyncSocket", [NSBundle mainBundle],
3529
                                                             @"Attempt to connect to host timed out", nil);
3530
 
3531
        NSDictionary *userInfo = @{NSLocalizedDescriptionKey : errMsg};
3532
 
3533
        return [NSError errorWithDomain:GCDAsyncSocketErrorDomain code:GCDAsyncSocketConnectTimeoutError userInfo:userInfo];
3534
}
3535
 
3536
/**
3537
 * Returns a standard AsyncSocket maxed out error.
3538
**/
3539
- (NSError *)readMaxedOutError
3540
{
3541
        NSString *errMsg = NSLocalizedStringWithDefaultValue(@"GCDAsyncSocketReadMaxedOutError",
3542
                                                                                                                 @"GCDAsyncSocket", [NSBundle mainBundle],
3543
                                                                                                                 @"Read operation reached set maximum length", nil);
3544
 
3545
        NSDictionary *info = @{NSLocalizedDescriptionKey : errMsg};
3546
 
3547
        return [NSError errorWithDomain:GCDAsyncSocketErrorDomain code:GCDAsyncSocketReadMaxedOutError userInfo:info];
3548
}
3549
 
3550
/**
3551
 * Returns a standard AsyncSocket write timeout error.
3552
**/
3553
- (NSError *)readTimeoutError
3554
{
3555
        NSString *errMsg = NSLocalizedStringWithDefaultValue(@"GCDAsyncSocketReadTimeoutError",
3556
                                                             @"GCDAsyncSocket", [NSBundle mainBundle],
3557
                                                             @"Read operation timed out", nil);
3558
 
3559
        NSDictionary *userInfo = @{NSLocalizedDescriptionKey : errMsg};
3560
 
3561
        return [NSError errorWithDomain:GCDAsyncSocketErrorDomain code:GCDAsyncSocketReadTimeoutError userInfo:userInfo];
3562
}
3563
 
3564
/**
3565
 * Returns a standard AsyncSocket write timeout error.
3566
**/
3567
- (NSError *)writeTimeoutError
3568
{
3569
        NSString *errMsg = NSLocalizedStringWithDefaultValue(@"GCDAsyncSocketWriteTimeoutError",
3570
                                                             @"GCDAsyncSocket", [NSBundle mainBundle],
3571
                                                             @"Write operation timed out", nil);
3572
 
3573
        NSDictionary *userInfo = @{NSLocalizedDescriptionKey : errMsg};
3574
 
3575
        return [NSError errorWithDomain:GCDAsyncSocketErrorDomain code:GCDAsyncSocketWriteTimeoutError userInfo:userInfo];
3576
}
3577
 
3578
- (NSError *)connectionClosedError
3579
{
3580
        NSString *errMsg = NSLocalizedStringWithDefaultValue(@"GCDAsyncSocketClosedError",
3581
                                                             @"GCDAsyncSocket", [NSBundle mainBundle],
3582
                                                             @"Socket closed by remote peer", nil);
3583
 
3584
        NSDictionary *userInfo = @{NSLocalizedDescriptionKey : errMsg};
3585
 
3586
        return [NSError errorWithDomain:GCDAsyncSocketErrorDomain code:GCDAsyncSocketClosedError userInfo:userInfo];
3587
}
3588
 
3589
- (NSError *)otherError:(NSString *)errMsg
3590
{
3591
        NSDictionary *userInfo = @{NSLocalizedDescriptionKey : errMsg};
3592
 
3593
        return [NSError errorWithDomain:GCDAsyncSocketErrorDomain code:GCDAsyncSocketOtherError userInfo:userInfo];
3594
}
3595
 
3596
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3597
#pragma mark Diagnostics
3598
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3599
 
3600
- (BOOL)isDisconnected
3601
{
3602
        __block BOOL result = NO;
3603
 
3604
        dispatch_block_t block = ^{
3605
        result = (self->flags & kSocketStarted) ? NO : YES;
3606
        };
3607
 
3608
        if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
3609
                block();
3610
        else
3611
                dispatch_sync(socketQueue, block);
3612
 
3613
        return result;
3614
}
3615
 
3616
- (BOOL)isConnected
3617
{
3618
        __block BOOL result = NO;
3619
 
3620
        dispatch_block_t block = ^{
3621
        result = (self->flags & kConnected) ? YES : NO;
3622
        };
3623
 
3624
        if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
3625
                block();
3626
        else
3627
                dispatch_sync(socketQueue, block);
3628
 
3629
        return result;
3630
}
3631
 
3632
- (NSString *)connectedHost
3633
{
3634
        if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
3635
        {
3636
                if (socket4FD != SOCKET_NULL)
3637
                        return [self connectedHostFromSocket4:socket4FD];
3638
                if (socket6FD != SOCKET_NULL)
3639
                        return [self connectedHostFromSocket6:socket6FD];
3640
 
3641
                return nil;
3642
        }
3643
        else
3644
        {
3645
                __block NSString *result = nil;
3646
 
3647
                dispatch_sync(socketQueue, ^{ @autoreleasepool {
3648
 
3649
            if (self->socket4FD != SOCKET_NULL)
3650
                result = [self connectedHostFromSocket4:self->socket4FD];
3651
            else if (self->socket6FD != SOCKET_NULL)
3652
                result = [self connectedHostFromSocket6:self->socket6FD];
3653
                }});
3654
 
3655
                return result;
3656
        }
3657
}
3658
 
3659
- (uint16_t)connectedPort
3660
{
3661
        if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
3662
        {
3663
                if (socket4FD != SOCKET_NULL)
3664
                        return [self connectedPortFromSocket4:socket4FD];
3665
                if (socket6FD != SOCKET_NULL)
3666
                        return [self connectedPortFromSocket6:socket6FD];
3667
 
3668
                return 0;
3669
        }
3670
        else
3671
        {
3672
                __block uint16_t result = 0;
3673
 
3674
                dispatch_sync(socketQueue, ^{
3675
                        // No need for autorelease pool
3676
 
3677
            if (self->socket4FD != SOCKET_NULL)
3678
                result = [self connectedPortFromSocket4:self->socket4FD];
3679
            else if (self->socket6FD != SOCKET_NULL)
3680
                result = [self connectedPortFromSocket6:self->socket6FD];
3681
                });
3682
 
3683
                return result;
3684
        }
3685
}
3686
 
3687
- (NSURL *)connectedUrl
3688
{
3689
        if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
3690
        {
3691
                if (socketUN != SOCKET_NULL)
3692
                        return [self connectedUrlFromSocketUN:socketUN];
3693
 
3694
                return nil;
3695
        }
3696
        else
3697
        {
3698
                __block NSURL *result = nil;
3699
 
3700
                dispatch_sync(socketQueue, ^{ @autoreleasepool {
3701
 
3702
            if (self->socketUN != SOCKET_NULL)
3703
                result = [self connectedUrlFromSocketUN:self->socketUN];
3704
                }});
3705
 
3706
                return result;
3707
        }
3708
}
3709
 
3710
- (NSString *)localHost
3711
{
3712
        if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
3713
        {
3714
                if (socket4FD != SOCKET_NULL)
3715
                        return [self localHostFromSocket4:socket4FD];
3716
                if (socket6FD != SOCKET_NULL)
3717
                        return [self localHostFromSocket6:socket6FD];
3718
 
3719
                return nil;
3720
        }
3721
        else
3722
        {
3723
                __block NSString *result = nil;
3724
 
3725
                dispatch_sync(socketQueue, ^{ @autoreleasepool {
3726
 
3727
            if (self->socket4FD != SOCKET_NULL)
3728
                result = [self localHostFromSocket4:self->socket4FD];
3729
            else if (self->socket6FD != SOCKET_NULL)
3730
                result = [self localHostFromSocket6:self->socket6FD];
3731
                }});
3732
 
3733
                return result;
3734
        }
3735
}
3736
 
3737
- (uint16_t)localPort
3738
{
3739
        if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
3740
        {
3741
                if (socket4FD != SOCKET_NULL)
3742
                        return [self localPortFromSocket4:socket4FD];
3743
                if (socket6FD != SOCKET_NULL)
3744
                        return [self localPortFromSocket6:socket6FD];
3745
 
3746
                return 0;
3747
        }
3748
        else
3749
        {
3750
                __block uint16_t result = 0;
3751
 
3752
                dispatch_sync(socketQueue, ^{
3753
                        // No need for autorelease pool
3754
 
3755
            if (self->socket4FD != SOCKET_NULL)
3756
                result = [self localPortFromSocket4:self->socket4FD];
3757
            else if (self->socket6FD != SOCKET_NULL)
3758
                result = [self localPortFromSocket6:self->socket6FD];
3759
                });
3760
 
3761
                return result;
3762
        }
3763
}
3764
 
3765
- (NSString *)connectedHost4
3766
{
3767
        if (socket4FD != SOCKET_NULL)
3768
                return [self connectedHostFromSocket4:socket4FD];
3769
 
3770
        return nil;
3771
}
3772
 
3773
- (NSString *)connectedHost6
3774
{
3775
        if (socket6FD != SOCKET_NULL)
3776
                return [self connectedHostFromSocket6:socket6FD];
3777
 
3778
        return nil;
3779
}
3780
 
3781
- (uint16_t)connectedPort4
3782
{
3783
        if (socket4FD != SOCKET_NULL)
3784
                return [self connectedPortFromSocket4:socket4FD];
3785
 
3786
        return 0;
3787
}
3788
 
3789
- (uint16_t)connectedPort6
3790
{
3791
        if (socket6FD != SOCKET_NULL)
3792
                return [self connectedPortFromSocket6:socket6FD];
3793
 
3794
        return 0;
3795
}
3796
 
3797
- (NSString *)localHost4
3798
{
3799
        if (socket4FD != SOCKET_NULL)
3800
                return [self localHostFromSocket4:socket4FD];
3801
 
3802
        return nil;
3803
}
3804
 
3805
- (NSString *)localHost6
3806
{
3807
        if (socket6FD != SOCKET_NULL)
3808
                return [self localHostFromSocket6:socket6FD];
3809
 
3810
        return nil;
3811
}
3812
 
3813
- (uint16_t)localPort4
3814
{
3815
        if (socket4FD != SOCKET_NULL)
3816
                return [self localPortFromSocket4:socket4FD];
3817
 
3818
        return 0;
3819
}
3820
 
3821
- (uint16_t)localPort6
3822
{
3823
        if (socket6FD != SOCKET_NULL)
3824
                return [self localPortFromSocket6:socket6FD];
3825
 
3826
        return 0;
3827
}
3828
 
3829
- (NSString *)connectedHostFromSocket4:(int)socketFD
3830
{
3831
        struct sockaddr_in sockaddr4;
3832
        socklen_t sockaddr4len = sizeof(sockaddr4);
3833
 
3834
        if (getpeername(socketFD, (struct sockaddr *)&sockaddr4, &sockaddr4len) < 0)
3835
        {
3836
                return nil;
3837
        }
3838
        return [[self class] hostFromSockaddr4:&sockaddr4];
3839
}
3840
 
3841
- (NSString *)connectedHostFromSocket6:(int)socketFD
3842
{
3843
        struct sockaddr_in6 sockaddr6;
3844
        socklen_t sockaddr6len = sizeof(sockaddr6);
3845
 
3846
        if (getpeername(socketFD, (struct sockaddr *)&sockaddr6, &sockaddr6len) < 0)
3847
        {
3848
                return nil;
3849
        }
3850
        return [[self class] hostFromSockaddr6:&sockaddr6];
3851
}
3852
 
3853
- (uint16_t)connectedPortFromSocket4:(int)socketFD
3854
{
3855
        struct sockaddr_in sockaddr4;
3856
        socklen_t sockaddr4len = sizeof(sockaddr4);
3857
 
3858
        if (getpeername(socketFD, (struct sockaddr *)&sockaddr4, &sockaddr4len) < 0)
3859
        {
3860
                return 0;
3861
        }
3862
        return [[self class] portFromSockaddr4:&sockaddr4];
3863
}
3864
 
3865
- (uint16_t)connectedPortFromSocket6:(int)socketFD
3866
{
3867
        struct sockaddr_in6 sockaddr6;
3868
        socklen_t sockaddr6len = sizeof(sockaddr6);
3869
 
3870
        if (getpeername(socketFD, (struct sockaddr *)&sockaddr6, &sockaddr6len) < 0)
3871
        {
3872
                return 0;
3873
        }
3874
        return [[self class] portFromSockaddr6:&sockaddr6];
3875
}
3876
 
3877
- (NSURL *)connectedUrlFromSocketUN:(int)socketFD
3878
{
3879
        struct sockaddr_un sockaddr;
3880
        socklen_t sockaddrlen = sizeof(sockaddr);
3881
 
3882
        if (getpeername(socketFD, (struct sockaddr *)&sockaddr, &sockaddrlen) < 0)
3883
        {
3884
                return 0;
3885
        }
3886
        return [[self class] urlFromSockaddrUN:&sockaddr];
3887
}
3888
 
3889
- (NSString *)localHostFromSocket4:(int)socketFD
3890
{
3891
        struct sockaddr_in sockaddr4;
3892
        socklen_t sockaddr4len = sizeof(sockaddr4);
3893
 
3894
        if (getsockname(socketFD, (struct sockaddr *)&sockaddr4, &sockaddr4len) < 0)
3895
        {
3896
                return nil;
3897
        }
3898
        return [[self class] hostFromSockaddr4:&sockaddr4];
3899
}
3900
 
3901
- (NSString *)localHostFromSocket6:(int)socketFD
3902
{
3903
        struct sockaddr_in6 sockaddr6;
3904
        socklen_t sockaddr6len = sizeof(sockaddr6);
3905
 
3906
        if (getsockname(socketFD, (struct sockaddr *)&sockaddr6, &sockaddr6len) < 0)
3907
        {
3908
                return nil;
3909
        }
3910
        return [[self class] hostFromSockaddr6:&sockaddr6];
3911
}
3912
 
3913
- (uint16_t)localPortFromSocket4:(int)socketFD
3914
{
3915
        struct sockaddr_in sockaddr4;
3916
        socklen_t sockaddr4len = sizeof(sockaddr4);
3917
 
3918
        if (getsockname(socketFD, (struct sockaddr *)&sockaddr4, &sockaddr4len) < 0)
3919
        {
3920
                return 0;
3921
        }
3922
        return [[self class] portFromSockaddr4:&sockaddr4];
3923
}
3924
 
3925
- (uint16_t)localPortFromSocket6:(int)socketFD
3926
{
3927
        struct sockaddr_in6 sockaddr6;
3928
        socklen_t sockaddr6len = sizeof(sockaddr6);
3929
 
3930
        if (getsockname(socketFD, (struct sockaddr *)&sockaddr6, &sockaddr6len) < 0)
3931
        {
3932
                return 0;
3933
        }
3934
        return [[self class] portFromSockaddr6:&sockaddr6];
3935
}
3936
 
3937
- (NSData *)connectedAddress
3938
{
3939
        __block NSData *result = nil;
3940
 
3941
        dispatch_block_t block = ^{
3942
        if (self->socket4FD != SOCKET_NULL)
3943
                {
3944
                        struct sockaddr_in sockaddr4;
3945
                        socklen_t sockaddr4len = sizeof(sockaddr4);
3946
 
3947
            if (getpeername(self->socket4FD, (struct sockaddr *)&sockaddr4, &sockaddr4len) == 0)
3948
                        {
3949
                                result = [[NSData alloc] initWithBytes:&sockaddr4 length:sockaddr4len];
3950
                        }
3951
                }
3952
 
3953
        if (self->socket6FD != SOCKET_NULL)
3954
                {
3955
                        struct sockaddr_in6 sockaddr6;
3956
                        socklen_t sockaddr6len = sizeof(sockaddr6);
3957
 
3958
            if (getpeername(self->socket6FD, (struct sockaddr *)&sockaddr6, &sockaddr6len) == 0)
3959
                        {
3960
                                result = [[NSData alloc] initWithBytes:&sockaddr6 length:sockaddr6len];
3961
                        }
3962
                }
3963
        };
3964
 
3965
        if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
3966
                block();
3967
        else
3968
                dispatch_sync(socketQueue, block);
3969
 
3970
        return result;
3971
}
3972
 
3973
- (NSData *)localAddress
3974
{
3975
        __block NSData *result = nil;
3976
 
3977
        dispatch_block_t block = ^{
3978
        if (self->socket4FD != SOCKET_NULL)
3979
                {
3980
                        struct sockaddr_in sockaddr4;
3981
                        socklen_t sockaddr4len = sizeof(sockaddr4);
3982
 
3983
            if (getsockname(self->socket4FD, (struct sockaddr *)&sockaddr4, &sockaddr4len) == 0)
3984
                        {
3985
                                result = [[NSData alloc] initWithBytes:&sockaddr4 length:sockaddr4len];
3986
                        }
3987
                }
3988
 
3989
        if (self->socket6FD != SOCKET_NULL)
3990
                {
3991
                        struct sockaddr_in6 sockaddr6;
3992
                        socklen_t sockaddr6len = sizeof(sockaddr6);
3993
 
3994
            if (getsockname(self->socket6FD, (struct sockaddr *)&sockaddr6, &sockaddr6len) == 0)
3995
                        {
3996
                                result = [[NSData alloc] initWithBytes:&sockaddr6 length:sockaddr6len];
3997
                        }
3998
                }
3999
        };
4000
 
4001
        if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
4002
                block();
4003
        else
4004
                dispatch_sync(socketQueue, block);
4005
 
4006
        return result;
4007
}
4008
 
4009
- (BOOL)isIPv4
4010
{
4011
        if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
4012
        {
4013
                return (socket4FD != SOCKET_NULL);
4014
        }
4015
        else
4016
        {
4017
                __block BOOL result = NO;
4018
 
4019
                dispatch_sync(socketQueue, ^{
4020
            result = (self->socket4FD != SOCKET_NULL);
4021
                });
4022
 
4023
                return result;
4024
        }
4025
}
4026
 
4027
- (BOOL)isIPv6
4028
{
4029
        if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
4030
        {
4031
                return (socket6FD != SOCKET_NULL);
4032
        }
4033
        else
4034
        {
4035
                __block BOOL result = NO;
4036
 
4037
                dispatch_sync(socketQueue, ^{
4038
            result = (self->socket6FD != SOCKET_NULL);
4039
                });
4040
 
4041
                return result;
4042
        }
4043
}
4044
 
4045
- (BOOL)isSecure
4046
{
4047
        if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
4048
        {
4049
                return (flags & kSocketSecure) ? YES : NO;
4050
        }
4051
        else
4052
        {
4053
                __block BOOL result;
4054
 
4055
                dispatch_sync(socketQueue, ^{
4056
            result = (self->flags & kSocketSecure) ? YES : NO;
4057
                });
4058
 
4059
                return result;
4060
        }
4061
}
4062
 
4063
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
4064
#pragma mark Utilities
4065
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
4066
 
4067
/**
4068
 * Finds the address of an interface description.
4069
 * An inteface description may be an interface name (en0, en1, lo0) or corresponding IP (192.168.4.34).
4070
 *
4071
 * The interface description may optionally contain a port number at the end, separated by a colon.
4072
 * If a non-zero port parameter is provided, any port number in the interface description is ignored.
4073
 *
4074
 * The returned value is a 'struct sockaddr' wrapped in an NSMutableData object.
4075
**/
4076
- (void)getInterfaceAddress4:(NSMutableData **)interfaceAddr4Ptr
4077
                    address6:(NSMutableData **)interfaceAddr6Ptr
4078
             fromDescription:(NSString *)interfaceDescription
4079
                        port:(uint16_t)port
4080
{
4081
        NSMutableData *addr4 = nil;
4082
        NSMutableData *addr6 = nil;
4083
 
4084
        NSString *interface = nil;
4085
 
4086
        NSArray *components = [interfaceDescription componentsSeparatedByString:@":"];
4087
        if ([components count] > 0)
4088
        {
4089
                NSString *temp = [components objectAtIndex:0];
4090
                if ([temp length] > 0)
4091
                {
4092
                        interface = temp;
4093
                }
4094
        }
4095
        if ([components count] > 1 && port == 0)
4096
        {
4097
                NSString *temp = [components objectAtIndex:1];
4098
                long portL = strtol([temp UTF8String], NULL, 10);
4099
 
4100
                if (portL > 0 && portL <= UINT16_MAX)
4101
                {
4102
                        port = (uint16_t)portL;
4103
                }
4104
        }
4105
 
4106
        if (interface == nil)
4107
        {
4108
                // ANY address
4109
 
4110
                struct sockaddr_in sockaddr4;
4111
                memset(&sockaddr4, 0, sizeof(sockaddr4));
4112
 
4113
                sockaddr4.sin_len         = sizeof(sockaddr4);
4114
                sockaddr4.sin_family      = AF_INET;
4115
                sockaddr4.sin_port        = htons(port);
4116
                sockaddr4.sin_addr.s_addr = htonl(INADDR_ANY);
4117
 
4118
                struct sockaddr_in6 sockaddr6;
4119
                memset(&sockaddr6, 0, sizeof(sockaddr6));
4120
 
4121
                sockaddr6.sin6_len       = sizeof(sockaddr6);
4122
                sockaddr6.sin6_family    = AF_INET6;
4123
                sockaddr6.sin6_port      = htons(port);
4124
                sockaddr6.sin6_addr      = in6addr_any;
4125
 
4126
                addr4 = [NSMutableData dataWithBytes:&sockaddr4 length:sizeof(sockaddr4)];
4127
                addr6 = [NSMutableData dataWithBytes:&sockaddr6 length:sizeof(sockaddr6)];
4128
        }
4129
        else if ([interface isEqualToString:@"localhost"] || [interface isEqualToString:@"loopback"])
4130
        {
4131
                // LOOPBACK address
4132
 
4133
                struct sockaddr_in sockaddr4;
4134
                memset(&sockaddr4, 0, sizeof(sockaddr4));
4135
 
4136
                sockaddr4.sin_len         = sizeof(sockaddr4);
4137
                sockaddr4.sin_family      = AF_INET;
4138
                sockaddr4.sin_port        = htons(port);
4139
                sockaddr4.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
4140
 
4141
                struct sockaddr_in6 sockaddr6;
4142
                memset(&sockaddr6, 0, sizeof(sockaddr6));
4143
 
4144
                sockaddr6.sin6_len       = sizeof(sockaddr6);
4145
                sockaddr6.sin6_family    = AF_INET6;
4146
                sockaddr6.sin6_port      = htons(port);
4147
                sockaddr6.sin6_addr      = in6addr_loopback;
4148
 
4149
                addr4 = [NSMutableData dataWithBytes:&sockaddr4 length:sizeof(sockaddr4)];
4150
                addr6 = [NSMutableData dataWithBytes:&sockaddr6 length:sizeof(sockaddr6)];
4151
        }
4152
        else
4153
        {
4154
                const char *iface = [interface UTF8String];
4155
 
4156
                struct ifaddrs *addrs;
4157
                const struct ifaddrs *cursor;
4158
 
4159
                if ((getifaddrs(&addrs) == 0))
4160
                {
4161
                        cursor = addrs;
4162
                        while (cursor != NULL)
4163
                        {
4164
                                if ((addr4 == nil) && (cursor->ifa_addr->sa_family == AF_INET))
4165
                                {
4166
                                        // IPv4
4167
 
4168
                                        struct sockaddr_in nativeAddr4;
4169
                                        memcpy(&nativeAddr4, cursor->ifa_addr, sizeof(nativeAddr4));
4170
 
4171
                                        if (strcmp(cursor->ifa_name, iface) == 0)
4172
                                        {
4173
                                                // Name match
4174
 
4175
                                                nativeAddr4.sin_port = htons(port);
4176
 
4177
                                                addr4 = [NSMutableData dataWithBytes:&nativeAddr4 length:sizeof(nativeAddr4)];
4178
                                        }
4179
                                        else
4180
                                        {
4181
                                                char ip[INET_ADDRSTRLEN];
4182
 
4183
                                                const char *conversion = inet_ntop(AF_INET, &nativeAddr4.sin_addr, ip, sizeof(ip));
4184
 
4185
                                                if ((conversion != NULL) && (strcmp(ip, iface) == 0))
4186
                                                {
4187
                                                        // IP match
4188
 
4189
                                                        nativeAddr4.sin_port = htons(port);
4190
 
4191
                                                        addr4 = [NSMutableData dataWithBytes:&nativeAddr4 length:sizeof(nativeAddr4)];
4192
                                                }
4193
                                        }
4194
                                }
4195
                                else if ((addr6 == nil) && (cursor->ifa_addr->sa_family == AF_INET6))
4196
                                {
4197
                                        // IPv6
4198
 
4199
                                        struct sockaddr_in6 nativeAddr6;
4200
                                        memcpy(&nativeAddr6, cursor->ifa_addr, sizeof(nativeAddr6));
4201
 
4202
                                        if (strcmp(cursor->ifa_name, iface) == 0)
4203
                                        {
4204
                                                // Name match
4205
 
4206
                                                nativeAddr6.sin6_port = htons(port);
4207
 
4208
                                                addr6 = [NSMutableData dataWithBytes:&nativeAddr6 length:sizeof(nativeAddr6)];
4209
                                        }
4210
                                        else
4211
                                        {
4212
                                                char ip[INET6_ADDRSTRLEN];
4213
 
4214
                                                const char *conversion = inet_ntop(AF_INET6, &nativeAddr6.sin6_addr, ip, sizeof(ip));
4215
 
4216
                                                if ((conversion != NULL) && (strcmp(ip, iface) == 0))
4217
                                                {
4218
                                                        // IP match
4219
 
4220
                                                        nativeAddr6.sin6_port = htons(port);
4221
 
4222
                                                        addr6 = [NSMutableData dataWithBytes:&nativeAddr6 length:sizeof(nativeAddr6)];
4223
                                                }
4224
                                        }
4225
                                }
4226
 
4227
                                cursor = cursor->ifa_next;
4228
                        }
4229
 
4230
                        freeifaddrs(addrs);
4231
                }
4232
        }
4233
 
4234
        if (interfaceAddr4Ptr) *interfaceAddr4Ptr = addr4;
4235
        if (interfaceAddr6Ptr) *interfaceAddr6Ptr = addr6;
4236
}
4237
 
4238
- (NSData *)getInterfaceAddressFromUrl:(NSURL *)url
4239
{
4240
        NSString *path = url.path;
4241
        if (path.length == 0) {
4242
                return nil;
4243
        }
4244
 
4245
    struct sockaddr_un nativeAddr;
4246
    nativeAddr.sun_family = AF_UNIX;
4247
    strlcpy(nativeAddr.sun_path, path.fileSystemRepresentation, sizeof(nativeAddr.sun_path));
4248
    nativeAddr.sun_len = (unsigned char)SUN_LEN(&nativeAddr);
4249
    NSData *interface = [NSData dataWithBytes:&nativeAddr length:sizeof(struct sockaddr_un)];
4250
 
4251
        return interface;
4252
}
4253
 
4254
- (void)setupReadAndWriteSourcesForNewlyConnectedSocket:(int)socketFD
4255
{
4256
        readSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, socketFD, 0, socketQueue);
4257
        writeSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_WRITE, socketFD, 0, socketQueue);
4258
 
4259
        // Setup event handlers
4260
 
4261
        __weak GCDAsyncSocket *weakSelf = self;
4262
 
4263
        dispatch_source_set_event_handler(readSource, ^{ @autoreleasepool {
4264
        #pragma clang diagnostic push
4265
        #pragma clang diagnostic warning "-Wimplicit-retain-self"
4266
 
4267
                __strong GCDAsyncSocket *strongSelf = weakSelf;
4268
                if (strongSelf == nil) return_from_block;
4269
 
4270
                LogVerbose(@"readEventBlock");
4271
 
4272
                strongSelf->socketFDBytesAvailable = dispatch_source_get_data(strongSelf->readSource);
4273
                LogVerbose(@"socketFDBytesAvailable: %lu", strongSelf->socketFDBytesAvailable);
4274
 
4275
                if (strongSelf->socketFDBytesAvailable > 0)
4276
                        [strongSelf doReadData];
4277
                else
4278
                        [strongSelf doReadEOF];
4279
 
4280
        #pragma clang diagnostic pop
4281
        }});
4282
 
4283
        dispatch_source_set_event_handler(writeSource, ^{ @autoreleasepool {
4284
        #pragma clang diagnostic push
4285
        #pragma clang diagnostic warning "-Wimplicit-retain-self"
4286
 
4287
                __strong GCDAsyncSocket *strongSelf = weakSelf;
4288
                if (strongSelf == nil) return_from_block;
4289
 
4290
                LogVerbose(@"writeEventBlock");
4291
 
4292
                strongSelf->flags |= kSocketCanAcceptBytes;
4293
                [strongSelf doWriteData];
4294
 
4295
        #pragma clang diagnostic pop
4296
        }});
4297
 
4298
        // Setup cancel handlers
4299
 
4300
        __block int socketFDRefCount = 2;
4301
 
4302
        #if !OS_OBJECT_USE_OBJC
4303
        dispatch_source_t theReadSource = readSource;
4304
        dispatch_source_t theWriteSource = writeSource;
4305
        #endif
4306
 
4307
        dispatch_source_set_cancel_handler(readSource, ^{
4308
        #pragma clang diagnostic push
4309
        #pragma clang diagnostic warning "-Wimplicit-retain-self"
4310
 
4311
                LogVerbose(@"readCancelBlock");
4312
 
4313
                #if !OS_OBJECT_USE_OBJC
4314
                LogVerbose(@"dispatch_release(readSource)");
4315
                dispatch_release(theReadSource);
4316
                #endif
4317
 
4318
                if (--socketFDRefCount == 0)
4319
                {
4320
                        LogVerbose(@"close(socketFD)");
4321
                        close(socketFD);
4322
                }
4323
 
4324
        #pragma clang diagnostic pop
4325
        });
4326
 
4327
        dispatch_source_set_cancel_handler(writeSource, ^{
4328
        #pragma clang diagnostic push
4329
        #pragma clang diagnostic warning "-Wimplicit-retain-self"
4330
 
4331
                LogVerbose(@"writeCancelBlock");
4332
 
4333
                #if !OS_OBJECT_USE_OBJC
4334
                LogVerbose(@"dispatch_release(writeSource)");
4335
                dispatch_release(theWriteSource);
4336
                #endif
4337
 
4338
                if (--socketFDRefCount == 0)
4339
                {
4340
                        LogVerbose(@"close(socketFD)");
4341
                        close(socketFD);
4342
                }
4343
 
4344
        #pragma clang diagnostic pop
4345
        });
4346
 
4347
        // We will not be able to read until data arrives.
4348
        // But we should be able to write immediately.
4349
 
4350
        socketFDBytesAvailable = 0;
4351
        flags &= ~kReadSourceSuspended;
4352
 
4353
        LogVerbose(@"dispatch_resume(readSource)");
4354
        dispatch_resume(readSource);
4355
 
4356
        flags |= kSocketCanAcceptBytes;
4357
        flags |= kWriteSourceSuspended;
4358
}
4359
 
4360
- (BOOL)usingCFStreamForTLS
4361
{
4362
        #if TARGET_OS_IPHONE
4363
 
4364
        if ((flags & kSocketSecure) && (flags & kUsingCFStreamForTLS))
4365
        {
4366
                // The startTLS method was given the GCDAsyncSocketUseCFStreamForTLS flag.
4367
 
4368
                return YES;
4369
        }
4370
 
4371
        #endif
4372
 
4373
        return NO;
4374
}
4375
 
4376
- (BOOL)usingSecureTransportForTLS
4377
{
4378
        // Invoking this method is equivalent to ![self usingCFStreamForTLS] (just more readable)
4379
 
4380
        #if TARGET_OS_IPHONE
4381
 
4382
        if ((flags & kSocketSecure) && (flags & kUsingCFStreamForTLS))
4383
        {
4384
                // The startTLS method was given the GCDAsyncSocketUseCFStreamForTLS flag.
4385
 
4386
                return NO;
4387
        }
4388
 
4389
        #endif
4390
 
4391
        return YES;
4392
}
4393
 
4394
- (void)suspendReadSource
4395
{
4396
        if (!(flags & kReadSourceSuspended))
4397
        {
4398
                LogVerbose(@"dispatch_suspend(readSource)");
4399
 
4400
                dispatch_suspend(readSource);
4401
                flags |= kReadSourceSuspended;
4402
        }
4403
}
4404
 
4405
- (void)resumeReadSource
4406
{
4407
        if (flags & kReadSourceSuspended)
4408
        {
4409
                LogVerbose(@"dispatch_resume(readSource)");
4410
 
4411
                dispatch_resume(readSource);
4412
                flags &= ~kReadSourceSuspended;
4413
        }
4414
}
4415
 
4416
- (void)suspendWriteSource
4417
{
4418
        if (!(flags & kWriteSourceSuspended))
4419
        {
4420
                LogVerbose(@"dispatch_suspend(writeSource)");
4421
 
4422
                dispatch_suspend(writeSource);
4423
                flags |= kWriteSourceSuspended;
4424
        }
4425
}
4426
 
4427
- (void)resumeWriteSource
4428
{
4429
        if (flags & kWriteSourceSuspended)
4430
        {
4431
                LogVerbose(@"dispatch_resume(writeSource)");
4432
 
4433
                dispatch_resume(writeSource);
4434
                flags &= ~kWriteSourceSuspended;
4435
        }
4436
}
4437
 
4438
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
4439
#pragma mark Reading
4440
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
4441
 
4442
- (void)readDataWithTimeout:(NSTimeInterval)timeout tag:(long)tag
4443
{
4444
        [self readDataWithTimeout:timeout buffer:nil bufferOffset:0 maxLength:0 tag:tag];
4445
}
4446
 
4447
- (void)readDataWithTimeout:(NSTimeInterval)timeout
4448
                     buffer:(NSMutableData *)buffer
4449
               bufferOffset:(NSUInteger)offset
4450
                        tag:(long)tag
4451
{
4452
        [self readDataWithTimeout:timeout buffer:buffer bufferOffset:offset maxLength:0 tag:tag];
4453
}
4454
 
4455
- (void)readDataWithTimeout:(NSTimeInterval)timeout
4456
                     buffer:(NSMutableData *)buffer
4457
               bufferOffset:(NSUInteger)offset
4458
                  maxLength:(NSUInteger)length
4459
                        tag:(long)tag
4460
{
4461
        if (offset > [buffer length]) {
4462
                LogWarn(@"Cannot read: offset > [buffer length]");
4463
                return;
4464
        }
4465
 
4466
        GCDAsyncReadPacket *packet = [[GCDAsyncReadPacket alloc] initWithData:buffer
4467
                                                                  startOffset:offset
4468
                                                                    maxLength:length
4469
                                                                      timeout:timeout
4470
                                                                   readLength:0
4471
                                                                   terminator:nil
4472
                                                                          tag:tag];
4473
 
4474
        dispatch_async(socketQueue, ^{ @autoreleasepool {
4475
 
4476
                LogTrace();
4477
 
4478
        if ((self->flags & kSocketStarted) && !(self->flags & kForbidReadsWrites))
4479
                {
4480
            [self->readQueue addObject:packet];
4481
                        [self maybeDequeueRead];
4482
                }
4483
        }});
4484
 
4485
        // Do not rely on the block being run in order to release the packet,
4486
        // as the queue might get released without the block completing.
4487
}
4488
 
4489
- (void)readDataToLength:(NSUInteger)length withTimeout:(NSTimeInterval)timeout tag:(long)tag
4490
{
4491
        [self readDataToLength:length withTimeout:timeout buffer:nil bufferOffset:0 tag:tag];
4492
}
4493
 
4494
- (void)readDataToLength:(NSUInteger)length
4495
             withTimeout:(NSTimeInterval)timeout
4496
                  buffer:(NSMutableData *)buffer
4497
            bufferOffset:(NSUInteger)offset
4498
                     tag:(long)tag
4499
{
4500
        if (length == 0) {
4501
                LogWarn(@"Cannot read: length == 0");
4502
                return;
4503
        }
4504
        if (offset > [buffer length]) {
4505
                LogWarn(@"Cannot read: offset > [buffer length]");
4506
                return;
4507
        }
4508
 
4509
        GCDAsyncReadPacket *packet = [[GCDAsyncReadPacket alloc] initWithData:buffer
4510
                                                                  startOffset:offset
4511
                                                                    maxLength:0
4512
                                                                      timeout:timeout
4513
                                                                   readLength:length
4514
                                                                   terminator:nil
4515
                                                                          tag:tag];
4516
 
4517
        dispatch_async(socketQueue, ^{ @autoreleasepool {
4518
 
4519
                LogTrace();
4520
 
4521
        if ((self->flags & kSocketStarted) && !(self->flags & kForbidReadsWrites))
4522
                {
4523
            [self->readQueue addObject:packet];
4524
                        [self maybeDequeueRead];
4525
                }
4526
        }});
4527
 
4528
        // Do not rely on the block being run in order to release the packet,
4529
        // as the queue might get released without the block completing.
4530
}
4531
 
4532
- (void)readDataToData:(NSData *)data withTimeout:(NSTimeInterval)timeout tag:(long)tag
4533
{
4534
        [self readDataToData:data withTimeout:timeout buffer:nil bufferOffset:0 maxLength:0 tag:tag];
4535
}
4536
 
4537
- (void)readDataToData:(NSData *)data
4538
           withTimeout:(NSTimeInterval)timeout
4539
                buffer:(NSMutableData *)buffer
4540
          bufferOffset:(NSUInteger)offset
4541
                   tag:(long)tag
4542
{
4543
        [self readDataToData:data withTimeout:timeout buffer:buffer bufferOffset:offset maxLength:0 tag:tag];
4544
}
4545
 
4546
- (void)readDataToData:(NSData *)data withTimeout:(NSTimeInterval)timeout maxLength:(NSUInteger)length tag:(long)tag
4547
{
4548
        [self readDataToData:data withTimeout:timeout buffer:nil bufferOffset:0 maxLength:length tag:tag];
4549
}
4550
 
4551
- (void)readDataToData:(NSData *)data
4552
           withTimeout:(NSTimeInterval)timeout
4553
                buffer:(NSMutableData *)buffer
4554
          bufferOffset:(NSUInteger)offset
4555
             maxLength:(NSUInteger)maxLength
4556
                   tag:(long)tag
4557
{
4558
        if ([data length] == 0) {
4559
                LogWarn(@"Cannot read: [data length] == 0");
4560
                return;
4561
        }
4562
        if (offset > [buffer length]) {
4563
                LogWarn(@"Cannot read: offset > [buffer length]");
4564
                return;
4565
        }
4566
        if (maxLength > 0 && maxLength < [data length]) {
4567
                LogWarn(@"Cannot read: maxLength > 0 && maxLength < [data length]");
4568
                return;
4569
        }
4570
 
4571
        GCDAsyncReadPacket *packet = [[GCDAsyncReadPacket alloc] initWithData:buffer
4572
                                                                  startOffset:offset
4573
                                                                    maxLength:maxLength
4574
                                                                      timeout:timeout
4575
                                                                   readLength:0
4576
                                                                   terminator:data
4577
                                                                          tag:tag];
4578
 
4579
        dispatch_async(socketQueue, ^{ @autoreleasepool {
4580
 
4581
                LogTrace();
4582
 
4583
        if ((self->flags & kSocketStarted) && !(self->flags & kForbidReadsWrites))
4584
                {
4585
            [self->readQueue addObject:packet];
4586
                        [self maybeDequeueRead];
4587
                }
4588
        }});
4589
 
4590
        // Do not rely on the block being run in order to release the packet,
4591
        // as the queue might get released without the block completing.
4592
}
4593
 
4594
- (float)progressOfReadReturningTag:(long *)tagPtr bytesDone:(NSUInteger *)donePtr total:(NSUInteger *)totalPtr
4595
{
4596
        __block float result = 0.0F;
4597
 
4598
        dispatch_block_t block = ^{
4599
 
4600
        if (!self->currentRead || ![self->currentRead isKindOfClass:[GCDAsyncReadPacket class]])
4601
                {
4602
                        // We're not reading anything right now.
4603
 
4604
                        if (tagPtr != NULL)   *tagPtr = 0;
4605
                        if (donePtr != NULL)  *donePtr = 0;
4606
                        if (totalPtr != NULL) *totalPtr = 0;
4607
 
4608
                        result = NAN;
4609
                }
4610
                else
4611
                {
4612
                        // It's only possible to know the progress of our read if we're reading to a certain length.
4613
                        // If we're reading to data, we of course have no idea when the data will arrive.
4614
                        // If we're reading to timeout, then we have no idea when the next chunk of data will arrive.
4615
 
4616
            NSUInteger done = self->currentRead->bytesDone;
4617
            NSUInteger total = self->currentRead->readLength;
4618
 
4619
            if (tagPtr != NULL)   *tagPtr = self->currentRead->tag;
4620
                        if (donePtr != NULL)  *donePtr = done;
4621
                        if (totalPtr != NULL) *totalPtr = total;
4622
 
4623
                        if (total > 0)
4624
                                result = (float)done / (float)total;
4625
                        else
4626
                                result = 1.0F;
4627
                }
4628
        };
4629
 
4630
        if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
4631
                block();
4632
        else
4633
                dispatch_sync(socketQueue, block);
4634
 
4635
        return result;
4636
}
4637
 
4638
/**
4639
 * This method starts a new read, if needed.
4640
 *
4641
 * It is called when:
4642
 * - a user requests a read
4643
 * - after a read request has finished (to handle the next request)
4644
 * - immediately after the socket opens to handle any pending requests
4645
 *
4646
 * This method also handles auto-disconnect post read/write completion.
4647
**/
4648
- (void)maybeDequeueRead
4649
{
4650
        LogTrace();
4651
        NSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @"Must be dispatched on socketQueue");
4652
 
4653
        // If we're not currently processing a read AND we have an available read stream
4654
        if ((currentRead == nil) && (flags & kConnected))
4655
        {
4656
                if ([readQueue count] > 0)
4657
                {
4658
                        // Dequeue the next object in the write queue
4659
                        currentRead = [readQueue objectAtIndex:0];
4660
                        [readQueue removeObjectAtIndex:0];
4661
 
4662
 
4663
                        if ([currentRead isKindOfClass:[GCDAsyncSpecialPacket class]])
4664
                        {
4665
                                LogVerbose(@"Dequeued GCDAsyncSpecialPacket");
4666
 
4667
                                // Attempt to start TLS
4668
                                flags |= kStartingReadTLS;
4669
 
4670
                                // This method won't do anything unless both kStartingReadTLS and kStartingWriteTLS are set
4671
                                [self maybeStartTLS];
4672
                        }
4673
                        else
4674
                        {
4675
                                LogVerbose(@"Dequeued GCDAsyncReadPacket");
4676
 
4677
                                // Setup read timer (if needed)
4678
                                [self setupReadTimerWithTimeout:currentRead->timeout];
4679
 
4680
                                // Immediately read, if possible
4681
                                [self doReadData];
4682
                        }
4683
                }
4684
                else if (flags & kDisconnectAfterReads)
4685
                {
4686
                        if (flags & kDisconnectAfterWrites)
4687
                        {
4688
                                if (([writeQueue count] == 0) && (currentWrite == nil))
4689
                                {
4690
                                        [self closeWithError:nil];
4691
                                }
4692
                        }
4693
                        else
4694
                        {
4695
                                [self closeWithError:nil];
4696
                        }
4697
                }
4698
                else if (flags & kSocketSecure)
4699
                {
4700
                        [self flushSSLBuffers];
4701
 
4702
                        // Edge case:
4703
                        //
4704
                        // We just drained all data from the ssl buffers,
4705
                        // and all known data from the socket (socketFDBytesAvailable).
4706
                        //
4707
                        // If we didn't get any data from this process,
4708
                        // then we may have reached the end of the TCP stream.
4709
                        //
4710
                        // Be sure callbacks are enabled so we're notified about a disconnection.
4711
 
4712
                        if ([preBuffer availableBytes] == 0)
4713
                        {
4714
                                if ([self usingCFStreamForTLS]) {
4715
                                        // Callbacks never disabled
4716
                                }
4717
                                else {
4718
                                        [self resumeReadSource];
4719
                                }
4720
                        }
4721
                }
4722
        }
4723
}
4724
 
4725
- (void)flushSSLBuffers
4726
{
4727
        LogTrace();
4728
 
4729
        NSAssert((flags & kSocketSecure), @"Cannot flush ssl buffers on non-secure socket");
4730
 
4731
        if ([preBuffer availableBytes] > 0)
4732
        {
4733
                // Only flush the ssl buffers if the prebuffer is empty.
4734
                // This is to avoid growing the prebuffer inifinitely large.
4735
 
4736
                return;
4737
        }
4738
 
4739
        #if TARGET_OS_IPHONE
4740
 
4741
        if ([self usingCFStreamForTLS])
4742
        {
4743
                if ((flags & kSecureSocketHasBytesAvailable) && CFReadStreamHasBytesAvailable(readStream))
4744
                {
4745
                        LogVerbose(@"%@ - Flushing ssl buffers into prebuffer...", THIS_METHOD);
4746
 
4747
                        CFIndex defaultBytesToRead = (1024 * 4);
4748
 
4749
                        [preBuffer ensureCapacityForWrite:defaultBytesToRead];
4750
 
4751
                        uint8_t *buffer = [preBuffer writeBuffer];
4752
 
4753
                        CFIndex result = CFReadStreamRead(readStream, buffer, defaultBytesToRead);
4754
                        LogVerbose(@"%@ - CFReadStreamRead(): result = %i", THIS_METHOD, (int)result);
4755
 
4756
                        if (result > 0)
4757
                        {
4758
                                [preBuffer didWrite:result];
4759
                        }
4760
 
4761
                        flags &= ~kSecureSocketHasBytesAvailable;
4762
                }
4763
 
4764
                return;
4765
        }
4766
 
4767
        #endif
4768
 
4769
        __block NSUInteger estimatedBytesAvailable = 0;
4770
 
4771
        dispatch_block_t updateEstimatedBytesAvailable = ^{
4772
 
4773
                // Figure out if there is any data available to be read
4774
                //
4775
                // socketFDBytesAvailable        <- Number of encrypted bytes we haven't read from the bsd socket
4776
                // [sslPreBuffer availableBytes] <- Number of encrypted bytes we've buffered from bsd socket
4777
                // sslInternalBufSize            <- Number of decrypted bytes SecureTransport has buffered
4778
                //
4779
                // We call the variable "estimated" because we don't know how many decrypted bytes we'll get
4780
                // from the encrypted bytes in the sslPreBuffer.
4781
                // However, we do know this is an upper bound on the estimation.
4782
 
4783
        estimatedBytesAvailable = self->socketFDBytesAvailable + [self->sslPreBuffer availableBytes];
4784
 
4785
                size_t sslInternalBufSize = 0;
4786
        SSLGetBufferedReadSize(self->sslContext, &sslInternalBufSize);
4787
 
4788
                estimatedBytesAvailable += sslInternalBufSize;
4789
        };
4790
 
4791
        updateEstimatedBytesAvailable();
4792
 
4793
        if (estimatedBytesAvailable > 0)
4794
        {
4795
                LogVerbose(@"%@ - Flushing ssl buffers into prebuffer...", THIS_METHOD);
4796
 
4797
                BOOL done = NO;
4798
                do
4799
                {
4800
                        LogVerbose(@"%@ - estimatedBytesAvailable = %lu", THIS_METHOD, (unsigned long)estimatedBytesAvailable);
4801
 
4802
                        // Make sure there's enough room in the prebuffer
4803
 
4804
                        [preBuffer ensureCapacityForWrite:estimatedBytesAvailable];
4805
 
4806
                        // Read data into prebuffer
4807
 
4808
                        uint8_t *buffer = [preBuffer writeBuffer];
4809
                        size_t bytesRead = 0;
4810
 
4811
                        OSStatus result = SSLRead(sslContext, buffer, (size_t)estimatedBytesAvailable, &bytesRead);
4812
                        LogVerbose(@"%@ - read from secure socket = %u", THIS_METHOD, (unsigned)bytesRead);
4813
 
4814
                        if (bytesRead > 0)
4815
                        {
4816
                                [preBuffer didWrite:bytesRead];
4817
                        }
4818
 
4819
                        LogVerbose(@"%@ - prebuffer.length = %zu", THIS_METHOD, [preBuffer availableBytes]);
4820
 
4821
                        if (result != noErr)
4822
                        {
4823
                                done = YES;
4824
                        }
4825
                        else
4826
                        {
4827
                                updateEstimatedBytesAvailable();
4828
                        }
4829
 
4830
                } while (!done && estimatedBytesAvailable > 0);
4831
        }
4832
}
4833
 
4834
- (void)doReadData
4835
{
4836
        LogTrace();
4837
 
4838
        // This method is called on the socketQueue.
4839
        // It might be called directly, or via the readSource when data is available to be read.
4840
 
4841
        if ((currentRead == nil) || (flags & kReadsPaused))
4842
        {
4843
                LogVerbose(@"No currentRead or kReadsPaused");
4844
 
4845
                // Unable to read at this time
4846
 
4847
                if (flags & kSocketSecure)
4848
                {
4849
                        // Here's the situation:
4850
                        //
4851
                        // We have an established secure connection.
4852
                        // There may not be a currentRead, but there might be encrypted data sitting around for us.
4853
                        // When the user does get around to issuing a read, that encrypted data will need to be decrypted.
4854
                        //
4855
                        // So why make the user wait?
4856
                        // We might as well get a head start on decrypting some data now.
4857
                        //
4858
                        // The other reason we do this has to do with detecting a socket disconnection.
4859
                        // The SSL/TLS protocol has it's own disconnection handshake.
4860
                        // So when a secure socket is closed, a "goodbye" packet comes across the wire.
4861
                        // We want to make sure we read the "goodbye" packet so we can properly detect the TCP disconnection.
4862
 
4863
                        [self flushSSLBuffers];
4864
                }
4865
 
4866
                if ([self usingCFStreamForTLS])
4867
                {
4868
                        // CFReadStream only fires once when there is available data.
4869
                        // It won't fire again until we've invoked CFReadStreamRead.
4870
                }
4871
                else
4872
                {
4873
                        // If the readSource is firing, we need to pause it
4874
                        // or else it will continue to fire over and over again.
4875
                        //
4876
                        // If the readSource is not firing,
4877
                        // we want it to continue monitoring the socket.
4878
 
4879
                        if (socketFDBytesAvailable > 0)
4880
                        {
4881
                                [self suspendReadSource];
4882
                        }
4883
                }
4884
                return;
4885
        }
4886
 
4887
        BOOL hasBytesAvailable = NO;
4888
        unsigned long estimatedBytesAvailable = 0;
4889
 
4890
        if ([self usingCFStreamForTLS])
4891
        {
4892
                #if TARGET_OS_IPHONE
4893
 
4894
                // Requested CFStream, rather than SecureTransport, for TLS (via GCDAsyncSocketUseCFStreamForTLS)
4895
 
4896
                estimatedBytesAvailable = 0;
4897
                if ((flags & kSecureSocketHasBytesAvailable) && CFReadStreamHasBytesAvailable(readStream))
4898
                        hasBytesAvailable = YES;
4899
                else
4900
                        hasBytesAvailable = NO;
4901
 
4902
                #endif
4903
        }
4904
        else
4905
        {
4906
                estimatedBytesAvailable = socketFDBytesAvailable;
4907
 
4908
                if (flags & kSocketSecure)
4909
                {
4910
                        // There are 2 buffers to be aware of here.
4911
                        //
4912
                        // We are using SecureTransport, a TLS/SSL security layer which sits atop TCP.
4913
                        // We issue a read to the SecureTranport API, which in turn issues a read to our SSLReadFunction.
4914
                        // Our SSLReadFunction then reads from the BSD socket and returns the encrypted data to SecureTransport.
4915
                        // SecureTransport then decrypts the data, and finally returns the decrypted data back to us.
4916
                        //
4917
                        // The first buffer is one we create.
4918
                        // SecureTransport often requests small amounts of data.
4919
                        // This has to do with the encypted packets that are coming across the TCP stream.
4920
                        // But it's non-optimal to do a bunch of small reads from the BSD socket.
4921
                        // So our SSLReadFunction reads all available data from the socket (optimizing the sys call)
4922
                        // and may store excess in the sslPreBuffer.
4923
 
4924
                        estimatedBytesAvailable += [sslPreBuffer availableBytes];
4925
 
4926
                        // The second buffer is within SecureTransport.
4927
                        // As mentioned earlier, there are encrypted packets coming across the TCP stream.
4928
                        // SecureTransport needs the entire packet to decrypt it.
4929
                        // But if the entire packet produces X bytes of decrypted data,
4930
                        // and we only asked SecureTransport for X/2 bytes of data,
4931
                        // it must store the extra X/2 bytes of decrypted data for the next read.
4932
                        //
4933
                        // The SSLGetBufferedReadSize function will tell us the size of this internal buffer.
4934
                        // From the documentation:
4935
                        //
4936
                        // "This function does not block or cause any low-level read operations to occur."
4937
 
4938
                        size_t sslInternalBufSize = 0;
4939
                        SSLGetBufferedReadSize(sslContext, &sslInternalBufSize);
4940
 
4941
                        estimatedBytesAvailable += sslInternalBufSize;
4942
                }
4943
 
4944
                hasBytesAvailable = (estimatedBytesAvailable > 0);
4945
        }
4946
 
4947
        if ((hasBytesAvailable == NO) && ([preBuffer availableBytes] == 0))
4948
        {
4949
                LogVerbose(@"No data available to read...");
4950
 
4951
                // No data available to read.
4952
 
4953
                if (![self usingCFStreamForTLS])
4954
                {
4955
                        // Need to wait for readSource to fire and notify us of
4956
                        // available data in the socket's internal read buffer.
4957
 
4958
                        [self resumeReadSource];
4959
                }
4960
                return;
4961
        }
4962
 
4963
        if (flags & kStartingReadTLS)
4964
        {
4965
                LogVerbose(@"Waiting for SSL/TLS handshake to complete");
4966
 
4967
                // The readQueue is waiting for SSL/TLS handshake to complete.
4968
 
4969
                if (flags & kStartingWriteTLS)
4970
                {
4971
                        if ([self usingSecureTransportForTLS] && lastSSLHandshakeError == errSSLWouldBlock)
4972
                        {
4973
                                // We are in the process of a SSL Handshake.
4974
                                // We were waiting for incoming data which has just arrived.
4975
 
4976
                                [self ssl_continueSSLHandshake];
4977
                        }
4978
                }
4979
                else
4980
                {
4981
                        // We are still waiting for the writeQueue to drain and start the SSL/TLS process.
4982
                        // We now know data is available to read.
4983
 
4984
                        if (![self usingCFStreamForTLS])
4985
                        {
4986
                                // Suspend the read source or else it will continue to fire nonstop.
4987
 
4988
                                [self suspendReadSource];
4989
                        }
4990
                }
4991
 
4992
                return;
4993
        }
4994
 
4995
        BOOL done        = NO;  // Completed read operation
4996
        NSError *error   = nil; // Error occurred
4997
 
4998
        NSUInteger totalBytesReadForCurrentRead = 0;
4999
 
5000
        //
5001
        // STEP 1 - READ FROM PREBUFFER
5002
        //
5003
 
5004
        if ([preBuffer availableBytes] > 0)
5005
        {
5006
                // There are 3 types of read packets:
5007
                //
5008
                // 1) Read all available data.
5009
                // 2) Read a specific length of data.
5010
                // 3) Read up to a particular terminator.
5011
 
5012
                NSUInteger bytesToCopy;
5013
 
5014
                if (currentRead->term != nil)
5015
                {
5016
                        // Read type #3 - read up to a terminator
5017
 
5018
                        bytesToCopy = [currentRead readLengthForTermWithPreBuffer:preBuffer found:&done];
5019
                }
5020
                else
5021
                {
5022
                        // Read type #1 or #2
5023
 
5024
                        bytesToCopy = [currentRead readLengthForNonTermWithHint:[preBuffer availableBytes]];
5025
                }
5026
 
5027
                // Make sure we have enough room in the buffer for our read.
5028
 
5029
                [currentRead ensureCapacityForAdditionalDataOfLength:bytesToCopy];
5030
 
5031
                // Copy bytes from prebuffer into packet buffer
5032
 
5033
                uint8_t *buffer = (uint8_t *)[currentRead->buffer mutableBytes] + currentRead->startOffset +
5034
                                                                                  currentRead->bytesDone;
5035
 
5036
                memcpy(buffer, [preBuffer readBuffer], bytesToCopy);
5037
 
5038
                // Remove the copied bytes from the preBuffer
5039
                [preBuffer didRead:bytesToCopy];
5040
 
5041
                LogVerbose(@"copied(%lu) preBufferLength(%zu)", (unsigned long)bytesToCopy, [preBuffer availableBytes]);
5042
 
5043
                // Update totals
5044
 
5045
                currentRead->bytesDone += bytesToCopy;
5046
                totalBytesReadForCurrentRead += bytesToCopy;
5047
 
5048
                // Check to see if the read operation is done
5049
 
5050
                if (currentRead->readLength > 0)
5051
                {
5052
                        // Read type #2 - read a specific length of data
5053
 
5054
                        done = (currentRead->bytesDone == currentRead->readLength);
5055
                }
5056
                else if (currentRead->term != nil)
5057
                {
5058
                        // Read type #3 - read up to a terminator
5059
 
5060
                        // Our 'done' variable was updated via the readLengthForTermWithPreBuffer:found: method
5061
 
5062
                        if (!done && currentRead->maxLength > 0)
5063
                        {
5064
                                // We're not done and there's a set maxLength.
5065
                                // Have we reached that maxLength yet?
5066
 
5067
                                if (currentRead->bytesDone >= currentRead->maxLength)
5068
                                {
5069
                                        error = [self readMaxedOutError];
5070
                                }
5071
                        }
5072
                }
5073
                else
5074
                {
5075
                        // Read type #1 - read all available data
5076
                        //
5077
                        // We're done as soon as
5078
                        // - we've read all available data (in prebuffer and socket)
5079
                        // - we've read the maxLength of read packet.
5080
 
5081
                        done = ((currentRead->maxLength > 0) && (currentRead->bytesDone == currentRead->maxLength));
5082
                }
5083
 
5084
        }
5085
 
5086
        //
5087
        // STEP 2 - READ FROM SOCKET
5088
        //
5089
 
5090
        BOOL socketEOF = (flags & kSocketHasReadEOF) ? YES : NO;  // Nothing more to read via socket (end of file)
5091
        BOOL waiting   = !done && !error && !socketEOF && !hasBytesAvailable; // Ran out of data, waiting for more
5092
 
5093
        if (!done && !error && !socketEOF && hasBytesAvailable)
5094
        {
5095
                NSAssert(([preBuffer availableBytes] == 0), @"Invalid logic");
5096
 
5097
                BOOL readIntoPreBuffer = NO;
5098
                uint8_t *buffer = NULL;
5099
                size_t bytesRead = 0;
5100
 
5101
                if (flags & kSocketSecure)
5102
                {
5103
                        if ([self usingCFStreamForTLS])
5104
                        {
5105
                                #if TARGET_OS_IPHONE
5106
 
5107
                                // Using CFStream, rather than SecureTransport, for TLS
5108
 
5109
                                NSUInteger defaultReadLength = (1024 * 32);
5110
 
5111
                                NSUInteger bytesToRead = [currentRead optimalReadLengthWithDefault:defaultReadLength
5112
                                                                                   shouldPreBuffer:&readIntoPreBuffer];
5113
 
5114
                                // Make sure we have enough room in the buffer for our read.
5115
                                //
5116
                                // We are either reading directly into the currentRead->buffer,
5117
                                // or we're reading into the temporary preBuffer.
5118
 
5119
                                if (readIntoPreBuffer)
5120
                                {
5121
                                        [preBuffer ensureCapacityForWrite:bytesToRead];
5122
 
5123
                                        buffer = [preBuffer writeBuffer];
5124
                                }
5125
                                else
5126
                                {
5127
                                        [currentRead ensureCapacityForAdditionalDataOfLength:bytesToRead];
5128
 
5129
                                        buffer = (uint8_t *)[currentRead->buffer mutableBytes]
5130
                                               + currentRead->startOffset
5131
                                               + currentRead->bytesDone;
5132
                                }
5133
 
5134
                                // Read data into buffer
5135
 
5136
                                CFIndex result = CFReadStreamRead(readStream, buffer, (CFIndex)bytesToRead);
5137
                                LogVerbose(@"CFReadStreamRead(): result = %i", (int)result);
5138
 
5139
                                if (result < 0)
5140
                                {
5141
                                        error = (__bridge_transfer NSError *)CFReadStreamCopyError(readStream);
5142
                                }
5143
                                else if (result == 0)
5144
                                {
5145
                                        socketEOF = YES;
5146
                                }
5147
                                else
5148
                                {
5149
                                        waiting = YES;
5150
                                        bytesRead = (size_t)result;
5151
                                }
5152
 
5153
                                // We only know how many decrypted bytes were read.
5154
                                // The actual number of bytes read was likely more due to the overhead of the encryption.
5155
                                // So we reset our flag, and rely on the next callback to alert us of more data.
5156
                                flags &= ~kSecureSocketHasBytesAvailable;
5157
 
5158
                                #endif
5159
                        }
5160
                        else
5161
                        {
5162
                                // Using SecureTransport for TLS
5163
                                //
5164
                                // We know:
5165
                                // - how many bytes are available on the socket
5166
                                // - how many encrypted bytes are sitting in the sslPreBuffer
5167
                                // - how many decypted bytes are sitting in the sslContext
5168
                                //
5169
                                // But we do NOT know:
5170
                                // - how many encypted bytes are sitting in the sslContext
5171
                                //
5172
                                // So we play the regular game of using an upper bound instead.
5173
 
5174
                                NSUInteger defaultReadLength = (1024 * 32);
5175
 
5176
                                if (defaultReadLength < estimatedBytesAvailable) {
5177
                                        defaultReadLength = estimatedBytesAvailable + (1024 * 16);
5178
                                }
5179
 
5180
                                NSUInteger bytesToRead = [currentRead optimalReadLengthWithDefault:defaultReadLength
5181
                                                                                   shouldPreBuffer:&readIntoPreBuffer];
5182
 
5183
                                if (bytesToRead > SIZE_MAX) { // NSUInteger may be bigger than size_t
5184
                                        bytesToRead = SIZE_MAX;
5185
                                }
5186
 
5187
                                // Make sure we have enough room in the buffer for our read.
5188
                                //
5189
                                // We are either reading directly into the currentRead->buffer,
5190
                                // or we're reading into the temporary preBuffer.
5191
 
5192
                                if (readIntoPreBuffer)
5193
                                {
5194
                                        [preBuffer ensureCapacityForWrite:bytesToRead];
5195
 
5196
                                        buffer = [preBuffer writeBuffer];
5197
                                }
5198
                                else
5199
                                {
5200
                                        [currentRead ensureCapacityForAdditionalDataOfLength:bytesToRead];
5201
 
5202
                                        buffer = (uint8_t *)[currentRead->buffer mutableBytes]
5203
                                               + currentRead->startOffset
5204
                                               + currentRead->bytesDone;
5205
                                }
5206
 
5207
                                // The documentation from Apple states:
5208
                                //
5209
                                //     "a read operation might return errSSLWouldBlock,
5210
                                //      indicating that less data than requested was actually transferred"
5211
                                //
5212
                                // However, starting around 10.7, the function will sometimes return noErr,
5213
                                // even if it didn't read as much data as requested. So we need to watch out for that.
5214
 
5215
                                OSStatus result;
5216
                                do
5217
                                {
5218
                                        void *loop_buffer = buffer + bytesRead;
5219
                                        size_t loop_bytesToRead = (size_t)bytesToRead - bytesRead;
5220
                                        size_t loop_bytesRead = 0;
5221
 
5222
                                        result = SSLRead(sslContext, loop_buffer, loop_bytesToRead, &loop_bytesRead);
5223
                                        LogVerbose(@"read from secure socket = %u", (unsigned)loop_bytesRead);
5224
 
5225
                                        bytesRead += loop_bytesRead;
5226
 
5227
                                } while ((result == noErr) && (bytesRead < bytesToRead));
5228
 
5229
 
5230
                                if (result != noErr)
5231
                                {
5232
                                        if (result == errSSLWouldBlock)
5233
                                                waiting = YES;
5234
                                        else
5235
                                        {
5236
                                                if (result == errSSLClosedGraceful || result == errSSLClosedAbort)
5237
                                                {
5238
                                                        // We've reached the end of the stream.
5239
                                                        // Handle this the same way we would an EOF from the socket.
5240
                                                        socketEOF = YES;
5241
                                                        sslErrCode = result;
5242
                                                }
5243
                                                else
5244
                                                {
5245
                                                        error = [self sslError:result];
5246
                                                }
5247
                                        }
5248
                                        // It's possible that bytesRead > 0, even if the result was errSSLWouldBlock.
5249
                                        // This happens when the SSLRead function is able to read some data,
5250
                                        // but not the entire amount we requested.
5251
 
5252
                                        if (bytesRead <= 0)
5253
                                        {
5254
                                                bytesRead = 0;
5255
                                        }
5256
                                }
5257
 
5258
                                // Do not modify socketFDBytesAvailable.
5259
                                // It will be updated via the SSLReadFunction().
5260
                        }
5261
                }
5262
                else
5263
                {
5264
                        // Normal socket operation
5265
 
5266
                        NSUInteger bytesToRead;
5267
 
5268
                        // There are 3 types of read packets:
5269
                        //
5270
                        // 1) Read all available data.
5271
                        // 2) Read a specific length of data.
5272
                        // 3) Read up to a particular terminator.
5273
 
5274
                        if (currentRead->term != nil)
5275
                        {
5276
                                // Read type #3 - read up to a terminator
5277
 
5278
                                bytesToRead = [currentRead readLengthForTermWithHint:estimatedBytesAvailable
5279
                                                                     shouldPreBuffer:&readIntoPreBuffer];
5280
                        }
5281
                        else
5282
                        {
5283
                                // Read type #1 or #2
5284
 
5285
                                bytesToRead = [currentRead readLengthForNonTermWithHint:estimatedBytesAvailable];
5286
                        }
5287
 
5288
                        if (bytesToRead > SIZE_MAX) { // NSUInteger may be bigger than size_t (read param 3)
5289
                                bytesToRead = SIZE_MAX;
5290
                        }
5291
 
5292
                        // Make sure we have enough room in the buffer for our read.
5293
                        //
5294
                        // We are either reading directly into the currentRead->buffer,
5295
                        // or we're reading into the temporary preBuffer.
5296
 
5297
                        if (readIntoPreBuffer)
5298
                        {
5299
                                [preBuffer ensureCapacityForWrite:bytesToRead];
5300
 
5301
                                buffer = [preBuffer writeBuffer];
5302
                        }
5303
                        else
5304
                        {
5305
                                [currentRead ensureCapacityForAdditionalDataOfLength:bytesToRead];
5306
 
5307
                                buffer = (uint8_t *)[currentRead->buffer mutableBytes]
5308
                                       + currentRead->startOffset
5309
                                       + currentRead->bytesDone;
5310
                        }
5311
 
5312
                        // Read data into buffer
5313
 
5314
                        int socketFD = (socket4FD != SOCKET_NULL) ? socket4FD : (socket6FD != SOCKET_NULL) ? socket6FD : socketUN;
5315
 
5316
                        ssize_t result = read(socketFD, buffer, (size_t)bytesToRead);
5317
                        LogVerbose(@"read from socket = %i", (int)result);
5318
 
5319
                        if (result < 0)
5320
                        {
5321
                                if (errno == EWOULDBLOCK)
5322
                                        waiting = YES;
5323
                                else
5324
                                        error = [self errorWithErrno:errno reason:@"Error in read() function"];
5325
 
5326
                                socketFDBytesAvailable = 0;
5327
                        }
5328
                        else if (result == 0)
5329
                        {
5330
                                socketEOF = YES;
5331
                                socketFDBytesAvailable = 0;
5332
                        }
5333
                        else
5334
                        {
5335
                                bytesRead = result;
5336
 
5337
                                if (bytesRead < bytesToRead)
5338
                                {
5339
                                        // The read returned less data than requested.
5340
                                        // This means socketFDBytesAvailable was a bit off due to timing,
5341
                                        // because we read from the socket right when the readSource event was firing.
5342
                                        socketFDBytesAvailable = 0;
5343
                                }
5344
                                else
5345
                                {
5346
                                        if (socketFDBytesAvailable <= bytesRead)
5347
                                                socketFDBytesAvailable = 0;
5348
                                        else
5349
                                                socketFDBytesAvailable -= bytesRead;
5350
                                }
5351
 
5352
                                if (socketFDBytesAvailable == 0)
5353
                                {
5354
                                        waiting = YES;
5355
                                }
5356
                        }
5357
                }
5358
 
5359
                if (bytesRead > 0)
5360
                {
5361
                        // Check to see if the read operation is done
5362
 
5363
                        if (currentRead->readLength > 0)
5364
                        {
5365
                                // Read type #2 - read a specific length of data
5366
                                //
5367
                                // Note: We should never be using a prebuffer when we're reading a specific length of data.
5368
 
5369
                                NSAssert(readIntoPreBuffer == NO, @"Invalid logic");
5370
 
5371
                                currentRead->bytesDone += bytesRead;
5372
                                totalBytesReadForCurrentRead += bytesRead;
5373
 
5374
                                done = (currentRead->bytesDone == currentRead->readLength);
5375
                        }
5376
                        else if (currentRead->term != nil)
5377
                        {
5378
                                // Read type #3 - read up to a terminator
5379
 
5380
                                if (readIntoPreBuffer)
5381
                                {
5382
                                        // We just read a big chunk of data into the preBuffer
5383
 
5384
                                        [preBuffer didWrite:bytesRead];
5385
                                        LogVerbose(@"read data into preBuffer - preBuffer.length = %zu", [preBuffer availableBytes]);
5386
 
5387
                                        // Search for the terminating sequence
5388
 
5389
                                        NSUInteger bytesToCopy = [currentRead readLengthForTermWithPreBuffer:preBuffer found:&done];
5390
                                        LogVerbose(@"copying %lu bytes from preBuffer", (unsigned long)bytesToCopy);
5391
 
5392
                                        // Ensure there's room on the read packet's buffer
5393
 
5394
                                        [currentRead ensureCapacityForAdditionalDataOfLength:bytesToCopy];
5395
 
5396
                                        // Copy bytes from prebuffer into read buffer
5397
 
5398
                                        uint8_t *readBuf = (uint8_t *)[currentRead->buffer mutableBytes] + currentRead->startOffset
5399
                                                                                                         + currentRead->bytesDone;
5400
 
5401
                                        memcpy(readBuf, [preBuffer readBuffer], bytesToCopy);
5402
 
5403
                                        // Remove the copied bytes from the prebuffer
5404
                                        [preBuffer didRead:bytesToCopy];
5405
                                        LogVerbose(@"preBuffer.length = %zu", [preBuffer availableBytes]);
5406
 
5407
                                        // Update totals
5408
                                        currentRead->bytesDone += bytesToCopy;
5409
                                        totalBytesReadForCurrentRead += bytesToCopy;
5410
 
5411
                                        // Our 'done' variable was updated via the readLengthForTermWithPreBuffer:found: method above
5412
                                }
5413
                                else
5414
                                {
5415
                                        // We just read a big chunk of data directly into the packet's buffer.
5416
                                        // We need to move any overflow into the prebuffer.
5417
 
5418
                                        NSInteger overflow = [currentRead searchForTermAfterPreBuffering:bytesRead];
5419
 
5420
                                        if (overflow == 0)
5421
                                        {
5422
                                                // Perfect match!
5423
                                                // Every byte we read stays in the read buffer,
5424
                                                // and the last byte we read was the last byte of the term.
5425
 
5426
                                                currentRead->bytesDone += bytesRead;
5427
                                                totalBytesReadForCurrentRead += bytesRead;
5428
                                                done = YES;
5429
                                        }
5430
                                        else if (overflow > 0)
5431
                                        {
5432
                                                // The term was found within the data that we read,
5433
                                                // and there are extra bytes that extend past the end of the term.
5434
                                                // We need to move these excess bytes out of the read packet and into the prebuffer.
5435
 
5436
                                                NSInteger underflow = bytesRead - overflow;
5437
 
5438
                                                // Copy excess data into preBuffer
5439
 
5440
                                                LogVerbose(@"copying %ld overflow bytes into preBuffer", (long)overflow);
5441
                                                [preBuffer ensureCapacityForWrite:overflow];
5442
 
5443
                                                uint8_t *overflowBuffer = buffer + underflow;
5444
                                                memcpy([preBuffer writeBuffer], overflowBuffer, overflow);
5445
 
5446
                                                [preBuffer didWrite:overflow];
5447
                                                LogVerbose(@"preBuffer.length = %zu", [preBuffer availableBytes]);
5448
 
5449
                                                // Note: The completeCurrentRead method will trim the buffer for us.
5450
 
5451
                                                currentRead->bytesDone += underflow;
5452
                                                totalBytesReadForCurrentRead += underflow;
5453
                                                done = YES;
5454
                                        }
5455
                                        else
5456
                                        {
5457
                                                // The term was not found within the data that we read.
5458
 
5459
                                                currentRead->bytesDone += bytesRead;
5460
                                                totalBytesReadForCurrentRead += bytesRead;
5461
                                                done = NO;
5462
                                        }
5463
                                }
5464
 
5465
                                if (!done && currentRead->maxLength > 0)
5466
                                {
5467
                                        // We're not done and there's a set maxLength.
5468
                                        // Have we reached that maxLength yet?
5469
 
5470
                                        if (currentRead->bytesDone >= currentRead->maxLength)
5471
                                        {
5472
                                                error = [self readMaxedOutError];
5473
                                        }
5474
                                }
5475
                        }
5476
                        else
5477
                        {
5478
                                // Read type #1 - read all available data
5479
 
5480
                                if (readIntoPreBuffer)
5481
                                {
5482
                                        // We just read a chunk of data into the preBuffer
5483
 
5484
                                        [preBuffer didWrite:bytesRead];
5485
 
5486
                                        // Now copy the data into the read packet.
5487
                                        //
5488
                                        // Recall that we didn't read directly into the packet's buffer to avoid
5489
                                        // over-allocating memory since we had no clue how much data was available to be read.
5490
                                        //
5491
                                        // Ensure there's room on the read packet's buffer
5492
 
5493
                                        [currentRead ensureCapacityForAdditionalDataOfLength:bytesRead];
5494
 
5495
                                        // Copy bytes from prebuffer into read buffer
5496
 
5497
                                        uint8_t *readBuf = (uint8_t *)[currentRead->buffer mutableBytes] + currentRead->startOffset
5498
                                                                                                         + currentRead->bytesDone;
5499
 
5500
                                        memcpy(readBuf, [preBuffer readBuffer], bytesRead);
5501
 
5502
                                        // Remove the copied bytes from the prebuffer
5503
                                        [preBuffer didRead:bytesRead];
5504
 
5505
                                        // Update totals
5506
                                        currentRead->bytesDone += bytesRead;
5507
                                        totalBytesReadForCurrentRead += bytesRead;
5508
                                }
5509
                                else
5510
                                {
5511
                                        currentRead->bytesDone += bytesRead;
5512
                                        totalBytesReadForCurrentRead += bytesRead;
5513
                                }
5514
 
5515
                                done = YES;
5516
                        }
5517
 
5518
                } // if (bytesRead > 0)
5519
 
5520
        } // if (!done && !error && !socketEOF && hasBytesAvailable)
5521
 
5522
 
5523
        if (!done && currentRead->readLength == 0 && currentRead->term == nil)
5524
        {
5525
                // Read type #1 - read all available data
5526
                //
5527
                // We might arrive here if we read data from the prebuffer but not from the socket.
5528
 
5529
                done = (totalBytesReadForCurrentRead > 0);
5530
        }
5531
 
5532
        // Check to see if we're done, or if we've made progress
5533
 
5534
        if (done)
5535
        {
5536
                [self completeCurrentRead];
5537
 
5538
                if (!error && (!socketEOF || [preBuffer availableBytes] > 0))
5539
                {
5540
                        [self maybeDequeueRead];
5541
                }
5542
        }
5543
        else if (totalBytesReadForCurrentRead > 0)
5544
        {
5545
                // We're not done read type #2 or #3 yet, but we have read in some bytes
5546
                //
5547
                // We ensure that `waiting` is set in order to resume the readSource (if it is suspended). It is
5548
                // possible to reach this point and `waiting` not be set, if the current read's length is
5549
                // sufficiently large. In that case, we may have read to some upperbound successfully, but
5550
                // that upperbound could be smaller than the desired length.
5551
                waiting = YES;
5552
 
5553
                __strong id<GCDAsyncSocketDelegate> theDelegate = delegate;
5554
 
5555
                if (delegateQueue && [theDelegate respondsToSelector:@selector(socket:didReadPartialDataOfLength:tag:)])
5556
                {
5557
                        long theReadTag = currentRead->tag;
5558
 
5559
                        dispatch_async(delegateQueue, ^{ @autoreleasepool {
5560
 
5561
                                [theDelegate socket:self didReadPartialDataOfLength:totalBytesReadForCurrentRead tag:theReadTag];
5562
                        }});
5563
                }
5564
        }
5565
 
5566
        // Check for errors
5567
 
5568
        if (error)
5569
        {
5570
                [self closeWithError:error];
5571
        }
5572
        else if (socketEOF)
5573
        {
5574
                [self doReadEOF];
5575
        }
5576
        else if (waiting)
5577
        {
5578
                if (![self usingCFStreamForTLS])
5579
                {
5580
                        // Monitor the socket for readability (if we're not already doing so)
5581
                        [self resumeReadSource];
5582
                }
5583
        }
5584
 
5585
        // Do not add any code here without first adding return statements in the error cases above.
5586
}
5587
 
5588
- (void)doReadEOF
5589
{
5590
        LogTrace();
5591
 
5592
        // This method may be called more than once.
5593
        // If the EOF is read while there is still data in the preBuffer,
5594
        // then this method may be called continually after invocations of doReadData to see if it's time to disconnect.
5595
 
5596
        flags |= kSocketHasReadEOF;
5597
 
5598
        if (flags & kSocketSecure)
5599
        {
5600
                // If the SSL layer has any buffered data, flush it into the preBuffer now.
5601
 
5602
                [self flushSSLBuffers];
5603
        }
5604
 
5605
        BOOL shouldDisconnect = NO;
5606
        NSError *error = nil;
5607
 
5608
        if ((flags & kStartingReadTLS) || (flags & kStartingWriteTLS))
5609
        {
5610
                // We received an EOF during or prior to startTLS.
5611
                // The SSL/TLS handshake is now impossible, so this is an unrecoverable situation.
5612
 
5613
                shouldDisconnect = YES;
5614
 
5615
                if ([self usingSecureTransportForTLS])
5616
                {
5617
                        error = [self sslError:errSSLClosedAbort];
5618
                }
5619
        }
5620
        else if (flags & kReadStreamClosed)
5621
        {
5622
                // The preBuffer has already been drained.
5623
                // The config allows half-duplex connections.
5624
                // We've previously checked the socket, and it appeared writeable.
5625
                // So we marked the read stream as closed and notified the delegate.
5626
                //
5627
                // As per the half-duplex contract, the socket will be closed when a write fails,
5628
                // or when the socket is manually closed.
5629
 
5630
                shouldDisconnect = NO;
5631
        }
5632
        else if ([preBuffer availableBytes] > 0)
5633
        {
5634
                LogVerbose(@"Socket reached EOF, but there is still data available in prebuffer");
5635
 
5636
                // Although we won't be able to read any more data from the socket,
5637
                // there is existing data that has been prebuffered that we can read.
5638
 
5639
                shouldDisconnect = NO;
5640
        }
5641
        else if (config & kAllowHalfDuplexConnection)
5642
        {
5643
                // We just received an EOF (end of file) from the socket's read stream.
5644
                // This means the remote end of the socket (the peer we're connected to)
5645
                // has explicitly stated that it will not be sending us any more data.
5646
                //
5647
                // Query the socket to see if it is still writeable. (Perhaps the peer will continue reading data from us)
5648
 
5649
                int socketFD = (socket4FD != SOCKET_NULL) ? socket4FD : (socket6FD != SOCKET_NULL) ? socket6FD : socketUN;
5650
 
5651
                struct pollfd pfd[1];
5652
                pfd[0].fd = socketFD;
5653
                pfd[0].events = POLLOUT;
5654
                pfd[0].revents = 0;
5655
 
5656
                poll(pfd, 1, 0);
5657
 
5658
                if (pfd[0].revents & POLLOUT)
5659
                {
5660
                        // Socket appears to still be writeable
5661
 
5662
                        shouldDisconnect = NO;
5663
                        flags |= kReadStreamClosed;
5664
 
5665
                        // Notify the delegate that we're going half-duplex
5666
 
5667
                        __strong id<GCDAsyncSocketDelegate> theDelegate = delegate;
5668
 
5669
                        if (delegateQueue && [theDelegate respondsToSelector:@selector(socketDidCloseReadStream:)])
5670
                        {
5671
                                dispatch_async(delegateQueue, ^{ @autoreleasepool {
5672
 
5673
                                        [theDelegate socketDidCloseReadStream:self];
5674
                                }});
5675
                        }
5676
                }
5677
                else
5678
                {
5679
                        shouldDisconnect = YES;
5680
                }
5681
        }
5682
        else
5683
        {
5684
                shouldDisconnect = YES;
5685
        }
5686
 
5687
 
5688
        if (shouldDisconnect)
5689
        {
5690
                if (error == nil)
5691
                {
5692
                        if ([self usingSecureTransportForTLS])
5693
                        {
5694
                                if (sslErrCode != noErr && sslErrCode != errSSLClosedGraceful)
5695
                                {
5696
                                        error = [self sslError:sslErrCode];
5697
                                }
5698
                                else
5699
                                {
5700
                                        error = [self connectionClosedError];
5701
                                }
5702
                        }
5703
                        else
5704
                        {
5705
                                error = [self connectionClosedError];
5706
                        }
5707
                }
5708
                [self closeWithError:error];
5709
        }
5710
        else
5711
        {
5712
                if (![self usingCFStreamForTLS])
5713
                {
5714
                        // Suspend the read source (if needed)
5715
 
5716
                        [self suspendReadSource];
5717
                }
5718
        }
5719
}
5720
 
5721
- (void)completeCurrentRead
5722
{
5723
        LogTrace();
5724
 
5725
        NSAssert(currentRead, @"Trying to complete current read when there is no current read.");
5726
 
5727
 
5728
        NSData *result = nil;
5729
 
5730
        if (currentRead->bufferOwner)
5731
        {
5732
                // We created the buffer on behalf of the user.
5733
                // Trim our buffer to be the proper size.
5734
                [currentRead->buffer setLength:currentRead->bytesDone];
5735
 
5736
                result = currentRead->buffer;
5737
        }
5738
        else
5739
        {
5740
                // We did NOT create the buffer.
5741
                // The buffer is owned by the caller.
5742
                // Only trim the buffer if we had to increase its size.
5743
 
5744
                if ([currentRead->buffer length] > currentRead->originalBufferLength)
5745
                {
5746
                        NSUInteger readSize = currentRead->startOffset + currentRead->bytesDone;
5747
                        NSUInteger origSize = currentRead->originalBufferLength;
5748
 
5749
                        NSUInteger buffSize = MAX(readSize, origSize);
5750
 
5751
                        [currentRead->buffer setLength:buffSize];
5752
                }
5753
 
5754
                uint8_t *buffer = (uint8_t *)[currentRead->buffer mutableBytes] + currentRead->startOffset;
5755
 
5756
                result = [NSData dataWithBytesNoCopy:buffer length:currentRead->bytesDone freeWhenDone:NO];
5757
        }
5758
 
5759
        __strong id<GCDAsyncSocketDelegate> theDelegate = delegate;
5760
 
5761
        if (delegateQueue && [theDelegate respondsToSelector:@selector(socket:didReadData:withTag:)])
5762
        {
5763
                GCDAsyncReadPacket *theRead = currentRead; // Ensure currentRead retained since result may not own buffer
5764
 
5765
                dispatch_async(delegateQueue, ^{ @autoreleasepool {
5766
 
5767
                        [theDelegate socket:self didReadData:result withTag:theRead->tag];
5768
                }});
5769
        }
5770
 
5771
        [self endCurrentRead];
5772
}
5773
 
5774
- (void)endCurrentRead
5775
{
5776
        if (readTimer)
5777
        {
5778
                dispatch_source_cancel(readTimer);
5779
                readTimer = NULL;
5780
        }
5781
 
5782
        currentRead = nil;
5783
}
5784
 
5785
- (void)setupReadTimerWithTimeout:(NSTimeInterval)timeout
5786
{
5787
        if (timeout >= 0.0)
5788
        {
5789
                readTimer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, socketQueue);
5790
 
5791
                __weak GCDAsyncSocket *weakSelf = self;
5792
 
5793
                dispatch_source_set_event_handler(readTimer, ^{ @autoreleasepool {
5794
                #pragma clang diagnostic push
5795
                #pragma clang diagnostic warning "-Wimplicit-retain-self"
5796
 
5797
                        __strong GCDAsyncSocket *strongSelf = weakSelf;
5798
                        if (strongSelf == nil) return_from_block;
5799
 
5800
                        [strongSelf doReadTimeout];
5801
 
5802
                #pragma clang diagnostic pop
5803
                }});
5804
 
5805
                #if !OS_OBJECT_USE_OBJC
5806
                dispatch_source_t theReadTimer = readTimer;
5807
                dispatch_source_set_cancel_handler(readTimer, ^{
5808
                #pragma clang diagnostic push
5809
                #pragma clang diagnostic warning "-Wimplicit-retain-self"
5810
 
5811
                        LogVerbose(@"dispatch_release(readTimer)");
5812
                        dispatch_release(theReadTimer);
5813
 
5814
                #pragma clang diagnostic pop
5815
                });
5816
                #endif
5817
 
5818
                dispatch_time_t tt = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(timeout * NSEC_PER_SEC));
5819
 
5820
                dispatch_source_set_timer(readTimer, tt, DISPATCH_TIME_FOREVER, 0);
5821
                dispatch_resume(readTimer);
5822
        }
5823
}
5824
 
5825
- (void)doReadTimeout
5826
{
5827
        // This is a little bit tricky.
5828
        // Ideally we'd like to synchronously query the delegate about a timeout extension.
5829
        // But if we do so synchronously we risk a possible deadlock.
5830
        // So instead we have to do so asynchronously, and callback to ourselves from within the delegate block.
5831
 
5832
        flags |= kReadsPaused;
5833
 
5834
        __strong id<GCDAsyncSocketDelegate> theDelegate = delegate;
5835
 
5836
        if (delegateQueue && [theDelegate respondsToSelector:@selector(socket:shouldTimeoutReadWithTag:elapsed:bytesDone:)])
5837
        {
5838
                GCDAsyncReadPacket *theRead = currentRead;
5839
 
5840
                dispatch_async(delegateQueue, ^{ @autoreleasepool {
5841
 
5842
                        NSTimeInterval timeoutExtension = 0.0;
5843
 
5844
                        timeoutExtension = [theDelegate socket:self shouldTimeoutReadWithTag:theRead->tag
5845
                                                                                     elapsed:theRead->timeout
5846
                                                                                   bytesDone:theRead->bytesDone];
5847
 
5848
            dispatch_async(self->socketQueue, ^{ @autoreleasepool {
5849
 
5850
                                [self doReadTimeoutWithExtension:timeoutExtension];
5851
                        }});
5852
                }});
5853
        }
5854
        else
5855
        {
5856
                [self doReadTimeoutWithExtension:0.0];
5857
        }
5858
}
5859
 
5860
- (void)doReadTimeoutWithExtension:(NSTimeInterval)timeoutExtension
5861
{
5862
        if (currentRead)
5863
        {
5864
                if (timeoutExtension > 0.0)
5865
                {
5866
                        currentRead->timeout += timeoutExtension;
5867
 
5868
                        // Reschedule the timer
5869
                        dispatch_time_t tt = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(timeoutExtension * NSEC_PER_SEC));
5870
                        dispatch_source_set_timer(readTimer, tt, DISPATCH_TIME_FOREVER, 0);
5871
 
5872
                        // Unpause reads, and continue
5873
                        flags &= ~kReadsPaused;
5874
                        [self doReadData];
5875
                }
5876
                else
5877
                {
5878
                        LogVerbose(@"ReadTimeout");
5879
 
5880
                        [self closeWithError:[self readTimeoutError]];
5881
                }
5882
        }
5883
}
5884
 
5885
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
5886
#pragma mark Writing
5887
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
5888
 
5889
- (void)writeData:(NSData *)data withTimeout:(NSTimeInterval)timeout tag:(long)tag
5890
{
5891
        if ([data length] == 0) return;
5892
 
5893
        GCDAsyncWritePacket *packet = [[GCDAsyncWritePacket alloc] initWithData:data timeout:timeout tag:tag];
5894
 
5895
        dispatch_async(socketQueue, ^{ @autoreleasepool {
5896
 
5897
                LogTrace();
5898
 
5899
        if ((self->flags & kSocketStarted) && !(self->flags & kForbidReadsWrites))
5900
                {
5901
            [self->writeQueue addObject:packet];
5902
                        [self maybeDequeueWrite];
5903
                }
5904
        }});
5905
 
5906
        // Do not rely on the block being run in order to release the packet,
5907
        // as the queue might get released without the block completing.
5908
}
5909
 
5910
- (float)progressOfWriteReturningTag:(long *)tagPtr bytesDone:(NSUInteger *)donePtr total:(NSUInteger *)totalPtr
5911
{
5912
        __block float result = 0.0F;
5913
 
5914
        dispatch_block_t block = ^{
5915
 
5916
        if (!self->currentWrite || ![self->currentWrite isKindOfClass:[GCDAsyncWritePacket class]])
5917
                {
5918
                        // We're not writing anything right now.
5919
 
5920
                        if (tagPtr != NULL)   *tagPtr = 0;
5921
                        if (donePtr != NULL)  *donePtr = 0;
5922
                        if (totalPtr != NULL) *totalPtr = 0;
5923
 
5924
                        result = NAN;
5925
                }
5926
                else
5927
                {
5928
            NSUInteger done = self->currentWrite->bytesDone;
5929
            NSUInteger total = [self->currentWrite->buffer length];
5930
 
5931
            if (tagPtr != NULL)   *tagPtr = self->currentWrite->tag;
5932
                        if (donePtr != NULL)  *donePtr = done;
5933
                        if (totalPtr != NULL) *totalPtr = total;
5934
 
5935
                        result = (float)done / (float)total;
5936
                }
5937
        };
5938
 
5939
        if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
5940
                block();
5941
        else
5942
                dispatch_sync(socketQueue, block);
5943
 
5944
        return result;
5945
}
5946
 
5947
/**
5948
 * Conditionally starts a new write.
5949
 *
5950
 * It is called when:
5951
 * - a user requests a write
5952
 * - after a write request has finished (to handle the next request)
5953
 * - immediately after the socket opens to handle any pending requests
5954
 *
5955
 * This method also handles auto-disconnect post read/write completion.
5956
**/
5957
- (void)maybeDequeueWrite
5958
{
5959
        LogTrace();
5960
        NSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @"Must be dispatched on socketQueue");
5961
 
5962
 
5963
        // If we're not currently processing a write AND we have an available write stream
5964
        if ((currentWrite == nil) && (flags & kConnected))
5965
        {
5966
                if ([writeQueue count] > 0)
5967
                {
5968
                        // Dequeue the next object in the write queue
5969
                        currentWrite = [writeQueue objectAtIndex:0];
5970
                        [writeQueue removeObjectAtIndex:0];
5971
 
5972
 
5973
                        if ([currentWrite isKindOfClass:[GCDAsyncSpecialPacket class]])
5974
                        {
5975
                                LogVerbose(@"Dequeued GCDAsyncSpecialPacket");
5976
 
5977
                                // Attempt to start TLS
5978
                                flags |= kStartingWriteTLS;
5979
 
5980
                                // This method won't do anything unless both kStartingReadTLS and kStartingWriteTLS are set
5981
                                [self maybeStartTLS];
5982
                        }
5983
                        else
5984
                        {
5985
                                LogVerbose(@"Dequeued GCDAsyncWritePacket");
5986
 
5987
                                // Setup write timer (if needed)
5988
                                [self setupWriteTimerWithTimeout:currentWrite->timeout];
5989
 
5990
                                // Immediately write, if possible
5991
                                [self doWriteData];
5992
                        }
5993
                }
5994
                else if (flags & kDisconnectAfterWrites)
5995
                {
5996
                        if (flags & kDisconnectAfterReads)
5997
                        {
5998
                                if (([readQueue count] == 0) && (currentRead == nil))
5999
                                {
6000
                                        [self closeWithError:nil];
6001
                                }
6002
                        }
6003
                        else
6004
                        {
6005
                                [self closeWithError:nil];
6006
                        }
6007
                }
6008
        }
6009
}
6010
 
6011
- (void)doWriteData
6012
{
6013
        LogTrace();
6014
 
6015
        // This method is called by the writeSource via the socketQueue
6016
 
6017
        if ((currentWrite == nil) || (flags & kWritesPaused))
6018
        {
6019
                LogVerbose(@"No currentWrite or kWritesPaused");
6020
 
6021
                // Unable to write at this time
6022
 
6023
                if ([self usingCFStreamForTLS])
6024
                {
6025
                        // CFWriteStream only fires once when there is available data.
6026
                        // It won't fire again until we've invoked CFWriteStreamWrite.
6027
                }
6028
                else
6029
                {
6030
                        // If the writeSource is firing, we need to pause it
6031
                        // or else it will continue to fire over and over again.
6032
 
6033
                        if (flags & kSocketCanAcceptBytes)
6034
                        {
6035
                                [self suspendWriteSource];
6036
                        }
6037
                }
6038
                return;
6039
        }
6040
 
6041
        if (!(flags & kSocketCanAcceptBytes))
6042
        {
6043
                LogVerbose(@"No space available to write...");
6044
 
6045
                // No space available to write.
6046
 
6047
                if (![self usingCFStreamForTLS])
6048
                {
6049
                        // Need to wait for writeSource to fire and notify us of
6050
                        // available space in the socket's internal write buffer.
6051
 
6052
                        [self resumeWriteSource];
6053
                }
6054
                return;
6055
        }
6056
 
6057
        if (flags & kStartingWriteTLS)
6058
        {
6059
                LogVerbose(@"Waiting for SSL/TLS handshake to complete");
6060
 
6061
                // The writeQueue is waiting for SSL/TLS handshake to complete.
6062
 
6063
                if (flags & kStartingReadTLS)
6064
                {
6065
                        if ([self usingSecureTransportForTLS] && lastSSLHandshakeError == errSSLWouldBlock)
6066
                        {
6067
                                // We are in the process of a SSL Handshake.
6068
                                // We were waiting for available space in the socket's internal OS buffer to continue writing.
6069
 
6070
                                [self ssl_continueSSLHandshake];
6071
                        }
6072
                }
6073
                else
6074
                {
6075
                        // We are still waiting for the readQueue to drain and start the SSL/TLS process.
6076
                        // We now know we can write to the socket.
6077
 
6078
                        if (![self usingCFStreamForTLS])
6079
                        {
6080
                                // Suspend the write source or else it will continue to fire nonstop.
6081
 
6082
                                [self suspendWriteSource];
6083
                        }
6084
                }
6085
 
6086
                return;
6087
        }
6088
 
6089
        // Note: This method is not called if currentWrite is a GCDAsyncSpecialPacket (startTLS packet)
6090
 
6091
        BOOL waiting = NO;
6092
        NSError *error = nil;
6093
        size_t bytesWritten = 0;
6094
 
6095
        if (flags & kSocketSecure)
6096
        {
6097
                if ([self usingCFStreamForTLS])
6098
                {
6099
                        #if TARGET_OS_IPHONE
6100
 
6101
                        //
6102
                        // Writing data using CFStream (over internal TLS)
6103
                        //
6104
 
6105
                        const uint8_t *buffer = (const uint8_t *)[currentWrite->buffer bytes] + currentWrite->bytesDone;
6106
 
6107
                        NSUInteger bytesToWrite = [currentWrite->buffer length] - currentWrite->bytesDone;
6108
 
6109
                        if (bytesToWrite > SIZE_MAX) // NSUInteger may be bigger than size_t (write param 3)
6110
                        {
6111
                                bytesToWrite = SIZE_MAX;
6112
                        }
6113
 
6114
                        CFIndex result = CFWriteStreamWrite(writeStream, buffer, (CFIndex)bytesToWrite);
6115
                        LogVerbose(@"CFWriteStreamWrite(%lu) = %li", (unsigned long)bytesToWrite, result);
6116
 
6117
                        if (result < 0)
6118
                        {
6119
                                error = (__bridge_transfer NSError *)CFWriteStreamCopyError(writeStream);
6120
                        }
6121
                        else
6122
                        {
6123
                                bytesWritten = (size_t)result;
6124
 
6125
                                // We always set waiting to true in this scenario.
6126
                                // CFStream may have altered our underlying socket to non-blocking.
6127
                                // Thus if we attempt to write without a callback, we may end up blocking our queue.
6128
                                waiting = YES;
6129
                        }
6130
 
6131
                        #endif
6132
                }
6133
                else
6134
                {
6135
                        // We're going to use the SSLWrite function.
6136
                        //
6137
                        // OSStatus SSLWrite(SSLContextRef context, const void *data, size_t dataLength, size_t *processed)
6138
                        //
6139
                        // Parameters:
6140
                        // context     - An SSL session context reference.
6141
                        // data        - A pointer to the buffer of data to write.
6142
                        // dataLength  - The amount, in bytes, of data to write.
6143
                        // processed   - On return, the length, in bytes, of the data actually written.
6144
                        //
6145
                        // It sounds pretty straight-forward,
6146
                        // but there are a few caveats you should be aware of.
6147
                        //
6148
                        // The SSLWrite method operates in a non-obvious (and rather annoying) manner.
6149
                        // According to the documentation:
6150
                        //
6151
                        //   Because you may configure the underlying connection to operate in a non-blocking manner,
6152
                        //   a write operation might return errSSLWouldBlock, indicating that less data than requested
6153
                        //   was actually transferred. In this case, you should repeat the call to SSLWrite until some
6154
                        //   other result is returned.
6155
                        //
6156
                        // This sounds perfect, but when our SSLWriteFunction returns errSSLWouldBlock,
6157
                        // then the SSLWrite method returns (with the proper errSSLWouldBlock return value),
6158
                        // but it sets processed to dataLength !!
6159
                        //
6160
                        // In other words, if the SSLWrite function doesn't completely write all the data we tell it to,
6161
                        // then it doesn't tell us how many bytes were actually written. So, for example, if we tell it to
6162
                        // write 256 bytes then it might actually write 128 bytes, but then report 0 bytes written.
6163
                        //
6164
                        // You might be wondering:
6165
                        // If the SSLWrite function doesn't tell us how many bytes were written,
6166
                        // then how in the world are we supposed to update our parameters (buffer & bytesToWrite)
6167
                        // for the next time we invoke SSLWrite?
6168
                        //
6169
                        // The answer is that SSLWrite cached all the data we told it to write,
6170
                        // and it will push out that data next time we call SSLWrite.
6171
                        // If we call SSLWrite with new data, it will push out the cached data first, and then the new data.
6172
                        // If we call SSLWrite with empty data, then it will simply push out the cached data.
6173
                        //
6174
                        // For this purpose we're going to break large writes into a series of smaller writes.
6175
                        // This allows us to report progress back to the delegate.
6176
 
6177
                        OSStatus result;
6178
 
6179
                        BOOL hasCachedDataToWrite = (sslWriteCachedLength > 0);
6180
                        BOOL hasNewDataToWrite = YES;
6181
 
6182
                        if (hasCachedDataToWrite)
6183
                        {
6184
                                size_t processed = 0;
6185
 
6186
                                result = SSLWrite(sslContext, NULL, 0, &processed);
6187
 
6188
                                if (result == noErr)
6189
                                {
6190
                                        bytesWritten = sslWriteCachedLength;
6191
                                        sslWriteCachedLength = 0;
6192
 
6193
                                        if ([currentWrite->buffer length] == (currentWrite->bytesDone + bytesWritten))
6194
                                        {
6195
                                                // We've written all data for the current write.
6196
                                                hasNewDataToWrite = NO;
6197
                                        }
6198
                                }
6199
                                else
6200
                                {
6201
                                        if (result == errSSLWouldBlock)
6202
                                        {
6203
                                                waiting = YES;
6204
                                        }
6205
                                        else
6206
                                        {
6207
                                                error = [self sslError:result];
6208
                                        }
6209
 
6210
                                        // Can't write any new data since we were unable to write the cached data.
6211
                                        hasNewDataToWrite = NO;
6212
                                }
6213
                        }
6214
 
6215
                        if (hasNewDataToWrite)
6216
                        {
6217
                                const uint8_t *buffer = (const uint8_t *)[currentWrite->buffer bytes]
6218
                                                                        + currentWrite->bytesDone
6219
                                                                        + bytesWritten;
6220
 
6221
                                NSUInteger bytesToWrite = [currentWrite->buffer length] - currentWrite->bytesDone - bytesWritten;
6222
 
6223
                                if (bytesToWrite > SIZE_MAX) // NSUInteger may be bigger than size_t (write param 3)
6224
                                {
6225
                                        bytesToWrite = SIZE_MAX;
6226
                                }
6227
 
6228
                                size_t bytesRemaining = bytesToWrite;
6229
 
6230
                                BOOL keepLooping = YES;
6231
                                while (keepLooping)
6232
                                {
6233
                                        const size_t sslMaxBytesToWrite = 32768;
6234
                                        size_t sslBytesToWrite = MIN(bytesRemaining, sslMaxBytesToWrite);
6235
                                        size_t sslBytesWritten = 0;
6236
 
6237
                                        result = SSLWrite(sslContext, buffer, sslBytesToWrite, &sslBytesWritten);
6238
 
6239
                                        if (result == noErr)
6240
                                        {
6241
                                                buffer += sslBytesWritten;
6242
                                                bytesWritten += sslBytesWritten;
6243
                                                bytesRemaining -= sslBytesWritten;
6244
 
6245
                                                keepLooping = (bytesRemaining > 0);
6246
                                        }
6247
                                        else
6248
                                        {
6249
                                                if (result == errSSLWouldBlock)
6250
                                                {
6251
                                                        waiting = YES;
6252
                                                        sslWriteCachedLength = sslBytesToWrite;
6253
                                                }
6254
                                                else
6255
                                                {
6256
                                                        error = [self sslError:result];
6257
                                                }
6258
 
6259
                                                keepLooping = NO;
6260
                                        }
6261
 
6262
                                } // while (keepLooping)
6263
 
6264
                        } // if (hasNewDataToWrite)
6265
                }
6266
        }
6267
        else
6268
        {
6269
                //
6270
                // Writing data directly over raw socket
6271
                //
6272
 
6273
                int socketFD = (socket4FD != SOCKET_NULL) ? socket4FD : (socket6FD != SOCKET_NULL) ? socket6FD : socketUN;
6274
 
6275
                const uint8_t *buffer = (const uint8_t *)[currentWrite->buffer bytes] + currentWrite->bytesDone;
6276
 
6277
                NSUInteger bytesToWrite = [currentWrite->buffer length] - currentWrite->bytesDone;
6278
 
6279
                if (bytesToWrite > SIZE_MAX) // NSUInteger may be bigger than size_t (write param 3)
6280
                {
6281
                        bytesToWrite = SIZE_MAX;
6282
                }
6283
 
6284
                ssize_t result = write(socketFD, buffer, (size_t)bytesToWrite);
6285
                LogVerbose(@"wrote to socket = %zd", result);
6286
 
6287
                // Check results
6288
                if (result < 0)
6289
                {
6290
                        if (errno == EWOULDBLOCK)
6291
                        {
6292
                                waiting = YES;
6293
                        }
6294
                        else
6295
                        {
6296
                                error = [self errorWithErrno:errno reason:@"Error in write() function"];
6297
                        }
6298
                }
6299
                else
6300
                {
6301
                        bytesWritten = result;
6302
                }
6303
        }
6304
 
6305
        // We're done with our writing.
6306
        // If we explictly ran into a situation where the socket told us there was no room in the buffer,
6307
        // then we immediately resume listening for notifications.
6308
        //
6309
        // We must do this before we dequeue another write,
6310
        // as that may in turn invoke this method again.
6311
        //
6312
        // Note that if CFStream is involved, it may have maliciously put our socket in blocking mode.
6313
 
6314
        if (waiting)
6315
        {
6316
                flags &= ~kSocketCanAcceptBytes;
6317
 
6318
                if (![self usingCFStreamForTLS])
6319
                {
6320
                        [self resumeWriteSource];
6321
                }
6322
        }
6323
 
6324
        // Check our results
6325
 
6326
        BOOL done = NO;
6327
 
6328
        if (bytesWritten > 0)
6329
        {
6330
                // Update total amount read for the current write
6331
                currentWrite->bytesDone += bytesWritten;
6332
                LogVerbose(@"currentWrite->bytesDone = %lu", (unsigned long)currentWrite->bytesDone);
6333
 
6334
                // Is packet done?
6335
                done = (currentWrite->bytesDone == [currentWrite->buffer length]);
6336
        }
6337
 
6338
        if (done)
6339
        {
6340
                [self completeCurrentWrite];
6341
 
6342
                if (!error)
6343
                {
6344
                        dispatch_async(socketQueue, ^{ @autoreleasepool{
6345
 
6346
                                [self maybeDequeueWrite];
6347
                        }});
6348
                }
6349
        }
6350
        else
6351
        {
6352
                // We were unable to finish writing the data,
6353
                // so we're waiting for another callback to notify us of available space in the lower-level output buffer.
6354
 
6355
                if (!waiting && !error)
6356
                {
6357
                        // This would be the case if our write was able to accept some data, but not all of it.
6358
 
6359
                        flags &= ~kSocketCanAcceptBytes;
6360
 
6361
                        if (![self usingCFStreamForTLS])
6362
                        {
6363
                                [self resumeWriteSource];
6364
                        }
6365
                }
6366
 
6367
                if (bytesWritten > 0)
6368
                {
6369
                        // We're not done with the entire write, but we have written some bytes
6370
 
6371
                        __strong id<GCDAsyncSocketDelegate> theDelegate = delegate;
6372
 
6373
                        if (delegateQueue && [theDelegate respondsToSelector:@selector(socket:didWritePartialDataOfLength:tag:)])
6374
                        {
6375
                                long theWriteTag = currentWrite->tag;
6376
 
6377
                                dispatch_async(delegateQueue, ^{ @autoreleasepool {
6378
 
6379
                                        [theDelegate socket:self didWritePartialDataOfLength:bytesWritten tag:theWriteTag];
6380
                                }});
6381
                        }
6382
                }
6383
        }
6384
 
6385
        // Check for errors
6386
 
6387
        if (error)
6388
        {
6389
                [self closeWithError:[self errorWithErrno:errno reason:@"Error in write() function"]];
6390
        }
6391
 
6392
        // Do not add any code here without first adding a return statement in the error case above.
6393
}
6394
 
6395
- (void)completeCurrentWrite
6396
{
6397
        LogTrace();
6398
 
6399
        NSAssert(currentWrite, @"Trying to complete current write when there is no current write.");
6400
 
6401
 
6402
        __strong id<GCDAsyncSocketDelegate> theDelegate = delegate;
6403
 
6404
        if (delegateQueue && [theDelegate respondsToSelector:@selector(socket:didWriteDataWithTag:)])
6405
        {
6406
                long theWriteTag = currentWrite->tag;
6407
 
6408
                dispatch_async(delegateQueue, ^{ @autoreleasepool {
6409
 
6410
                        [theDelegate socket:self didWriteDataWithTag:theWriteTag];
6411
                }});
6412
        }
6413
 
6414
        [self endCurrentWrite];
6415
}
6416
 
6417
- (void)endCurrentWrite
6418
{
6419
        if (writeTimer)
6420
        {
6421
                dispatch_source_cancel(writeTimer);
6422
                writeTimer = NULL;
6423
        }
6424
 
6425
        currentWrite = nil;
6426
}
6427
 
6428
- (void)setupWriteTimerWithTimeout:(NSTimeInterval)timeout
6429
{
6430
        if (timeout >= 0.0)
6431
        {
6432
                writeTimer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, socketQueue);
6433
 
6434
                __weak GCDAsyncSocket *weakSelf = self;
6435
 
6436
                dispatch_source_set_event_handler(writeTimer, ^{ @autoreleasepool {
6437
                #pragma clang diagnostic push
6438
                #pragma clang diagnostic warning "-Wimplicit-retain-self"
6439
 
6440
                        __strong GCDAsyncSocket *strongSelf = weakSelf;
6441
                        if (strongSelf == nil) return_from_block;
6442
 
6443
                        [strongSelf doWriteTimeout];
6444
 
6445
                #pragma clang diagnostic pop
6446
                }});
6447
 
6448
                #if !OS_OBJECT_USE_OBJC
6449
                dispatch_source_t theWriteTimer = writeTimer;
6450
                dispatch_source_set_cancel_handler(writeTimer, ^{
6451
                #pragma clang diagnostic push
6452
                #pragma clang diagnostic warning "-Wimplicit-retain-self"
6453
 
6454
                        LogVerbose(@"dispatch_release(writeTimer)");
6455
                        dispatch_release(theWriteTimer);
6456
 
6457
                #pragma clang diagnostic pop
6458
                });
6459
                #endif
6460
 
6461
                dispatch_time_t tt = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(timeout * NSEC_PER_SEC));
6462
 
6463
                dispatch_source_set_timer(writeTimer, tt, DISPATCH_TIME_FOREVER, 0);
6464
                dispatch_resume(writeTimer);
6465
        }
6466
}
6467
 
6468
- (void)doWriteTimeout
6469
{
6470
        // This is a little bit tricky.
6471
        // Ideally we'd like to synchronously query the delegate about a timeout extension.
6472
        // But if we do so synchronously we risk a possible deadlock.
6473
        // So instead we have to do so asynchronously, and callback to ourselves from within the delegate block.
6474
 
6475
        flags |= kWritesPaused;
6476
 
6477
        __strong id<GCDAsyncSocketDelegate> theDelegate = delegate;
6478
 
6479
        if (delegateQueue && [theDelegate respondsToSelector:@selector(socket:shouldTimeoutWriteWithTag:elapsed:bytesDone:)])
6480
        {
6481
                GCDAsyncWritePacket *theWrite = currentWrite;
6482
 
6483
                dispatch_async(delegateQueue, ^{ @autoreleasepool {
6484
 
6485
                        NSTimeInterval timeoutExtension = 0.0;
6486
 
6487
                        timeoutExtension = [theDelegate socket:self shouldTimeoutWriteWithTag:theWrite->tag
6488
                                                                                      elapsed:theWrite->timeout
6489
                                                                                    bytesDone:theWrite->bytesDone];
6490
 
6491
            dispatch_async(self->socketQueue, ^{ @autoreleasepool {
6492
 
6493
                                [self doWriteTimeoutWithExtension:timeoutExtension];
6494
                        }});
6495
                }});
6496
        }
6497
        else
6498
        {
6499
                [self doWriteTimeoutWithExtension:0.0];
6500
        }
6501
}
6502
 
6503
- (void)doWriteTimeoutWithExtension:(NSTimeInterval)timeoutExtension
6504
{
6505
        if (currentWrite)
6506
        {
6507
                if (timeoutExtension > 0.0)
6508
                {
6509
                        currentWrite->timeout += timeoutExtension;
6510
 
6511
                        // Reschedule the timer
6512
                        dispatch_time_t tt = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(timeoutExtension * NSEC_PER_SEC));
6513
                        dispatch_source_set_timer(writeTimer, tt, DISPATCH_TIME_FOREVER, 0);
6514
 
6515
                        // Unpause writes, and continue
6516
                        flags &= ~kWritesPaused;
6517
                        [self doWriteData];
6518
                }
6519
                else
6520
                {
6521
                        LogVerbose(@"WriteTimeout");
6522
 
6523
                        [self closeWithError:[self writeTimeoutError]];
6524
                }
6525
        }
6526
}
6527
 
6528
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
6529
#pragma mark Security
6530
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
6531
 
6532
- (void)startTLS:(NSDictionary *)tlsSettings
6533
{
6534
        LogTrace();
6535
 
6536
        if (tlsSettings == nil)
6537
    {
6538
        // Passing nil/NULL to CFReadStreamSetProperty will appear to work the same as passing an empty dictionary,
6539
        // but causes problems if we later try to fetch the remote host's certificate.
6540
        //
6541
        // To be exact, it causes the following to return NULL instead of the normal result:
6542
        // CFReadStreamCopyProperty(readStream, kCFStreamPropertySSLPeerCertificates)
6543
        //
6544
        // So we use an empty dictionary instead, which works perfectly.
6545
 
6546
        tlsSettings = [NSDictionary dictionary];
6547
    }
6548
 
6549
        GCDAsyncSpecialPacket *packet = [[GCDAsyncSpecialPacket alloc] initWithTLSSettings:tlsSettings];
6550
 
6551
        dispatch_async(socketQueue, ^{ @autoreleasepool {
6552
 
6553
        if ((self->flags & kSocketStarted) && !(self->flags & kQueuedTLS) && !(self->flags & kForbidReadsWrites))
6554
                {
6555
            [self->readQueue addObject:packet];
6556
            [self->writeQueue addObject:packet];
6557
 
6558
            self->flags |= kQueuedTLS;
6559
 
6560
                        [self maybeDequeueRead];
6561
                        [self maybeDequeueWrite];
6562
                }
6563
        }});
6564
 
6565
}
6566
 
6567
- (void)maybeStartTLS
6568
{
6569
        // We can't start TLS until:
6570
        // - All queued reads prior to the user calling startTLS are complete
6571
        // - All queued writes prior to the user calling startTLS are complete
6572
        //
6573
        // We'll know these conditions are met when both kStartingReadTLS and kStartingWriteTLS are set
6574
 
6575
        if ((flags & kStartingReadTLS) && (flags & kStartingWriteTLS))
6576
        {
6577
                BOOL useSecureTransport = YES;
6578
 
6579
                #if TARGET_OS_IPHONE
6580
                {
6581
                        GCDAsyncSpecialPacket *tlsPacket = (GCDAsyncSpecialPacket *)currentRead;
6582
            NSDictionary *tlsSettings = @{};
6583
            if (tlsPacket) {
6584
                tlsSettings = tlsPacket->tlsSettings;
6585
            }
6586
                        NSNumber *value = [tlsSettings objectForKey:GCDAsyncSocketUseCFStreamForTLS];
6587
                        if (value && [value boolValue])
6588
                                useSecureTransport = NO;
6589
                }
6590
                #endif
6591
 
6592
                if (useSecureTransport)
6593
                {
6594
                        [self ssl_startTLS];
6595
                }
6596
                else
6597
                {
6598
                #if TARGET_OS_IPHONE
6599
                        [self cf_startTLS];
6600
                #endif
6601
                }
6602
        }
6603
}
6604
 
6605
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
6606
#pragma mark Security via SecureTransport
6607
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
6608
 
6609
- (OSStatus)sslReadWithBuffer:(void *)buffer length:(size_t *)bufferLength
6610
{
6611
        LogVerbose(@"sslReadWithBuffer:%p length:%lu", buffer, (unsigned long)*bufferLength);
6612
 
6613
        if ((socketFDBytesAvailable == 0) && ([sslPreBuffer availableBytes] == 0))
6614
        {
6615
                LogVerbose(@"%@ - No data available to read...", THIS_METHOD);
6616
 
6617
                // No data available to read.
6618
                //
6619
                // Need to wait for readSource to fire and notify us of
6620
                // available data in the socket's internal read buffer.
6621
 
6622
                [self resumeReadSource];
6623
 
6624
                *bufferLength = 0;
6625
                return errSSLWouldBlock;
6626
        }
6627
 
6628
        size_t totalBytesRead = 0;
6629
        size_t totalBytesLeftToBeRead = *bufferLength;
6630
 
6631
        BOOL done = NO;
6632
        BOOL socketError = NO;
6633
 
6634
        //
6635
        // STEP 1 : READ FROM SSL PRE BUFFER
6636
        //
6637
 
6638
        size_t sslPreBufferLength = [sslPreBuffer availableBytes];
6639
 
6640
        if (sslPreBufferLength > 0)
6641
        {
6642
                LogVerbose(@"%@: Reading from SSL pre buffer...", THIS_METHOD);
6643
 
6644
                size_t bytesToCopy;
6645
                if (sslPreBufferLength > totalBytesLeftToBeRead)
6646
                        bytesToCopy = totalBytesLeftToBeRead;
6647
                else
6648
                        bytesToCopy = sslPreBufferLength;
6649
 
6650
                LogVerbose(@"%@: Copying %zu bytes from sslPreBuffer", THIS_METHOD, bytesToCopy);
6651
 
6652
                memcpy(buffer, [sslPreBuffer readBuffer], bytesToCopy);
6653
                [sslPreBuffer didRead:bytesToCopy];
6654
 
6655
                LogVerbose(@"%@: sslPreBuffer.length = %zu", THIS_METHOD, [sslPreBuffer availableBytes]);
6656
 
6657
                totalBytesRead += bytesToCopy;
6658
                totalBytesLeftToBeRead -= bytesToCopy;
6659
 
6660
                done = (totalBytesLeftToBeRead == 0);
6661
 
6662
                if (done) LogVerbose(@"%@: Complete", THIS_METHOD);
6663
        }
6664
 
6665
        //
6666
        // STEP 2 : READ FROM SOCKET
6667
        //
6668
 
6669
        if (!done && (socketFDBytesAvailable > 0))
6670
        {
6671
                LogVerbose(@"%@: Reading from socket...", THIS_METHOD);
6672
 
6673
                int socketFD = (socket4FD != SOCKET_NULL) ? socket4FD : (socket6FD != SOCKET_NULL) ? socket6FD : socketUN;
6674
 
6675
                BOOL readIntoPreBuffer;
6676
                size_t bytesToRead;
6677
                uint8_t *buf;
6678
 
6679
                if (socketFDBytesAvailable > totalBytesLeftToBeRead)
6680
                {
6681
                        // Read all available data from socket into sslPreBuffer.
6682
                        // Then copy requested amount into dataBuffer.
6683
 
6684
                        LogVerbose(@"%@: Reading into sslPreBuffer...", THIS_METHOD);
6685
 
6686
                        [sslPreBuffer ensureCapacityForWrite:socketFDBytesAvailable];
6687
 
6688
                        readIntoPreBuffer = YES;
6689
                        bytesToRead = (size_t)socketFDBytesAvailable;
6690
                        buf = [sslPreBuffer writeBuffer];
6691
                }
6692
                else
6693
                {
6694
                        // Read available data from socket directly into dataBuffer.
6695
 
6696
                        LogVerbose(@"%@: Reading directly into dataBuffer...", THIS_METHOD);
6697
 
6698
                        readIntoPreBuffer = NO;
6699
                        bytesToRead = totalBytesLeftToBeRead;
6700
                        buf = (uint8_t *)buffer + totalBytesRead;
6701
                }
6702
 
6703
                ssize_t result = read(socketFD, buf, bytesToRead);
6704
                LogVerbose(@"%@: read from socket = %zd", THIS_METHOD, result);
6705
 
6706
                if (result < 0)
6707
                {
6708
                        LogVerbose(@"%@: read errno = %i", THIS_METHOD, errno);
6709
 
6710
                        if (errno != EWOULDBLOCK)
6711
                        {
6712
                                socketError = YES;
6713
                        }
6714
 
6715
                        socketFDBytesAvailable = 0;
6716
                }
6717
                else if (result == 0)
6718
                {
6719
                        LogVerbose(@"%@: read EOF", THIS_METHOD);
6720
 
6721
                        socketError = YES;
6722
                        socketFDBytesAvailable = 0;
6723
                }
6724
                else
6725
                {
6726
                        size_t bytesReadFromSocket = result;
6727
 
6728
                        if (socketFDBytesAvailable > bytesReadFromSocket)
6729
                                socketFDBytesAvailable -= bytesReadFromSocket;
6730
                        else
6731
                                socketFDBytesAvailable = 0;
6732
 
6733
                        if (readIntoPreBuffer)
6734
                        {
6735
                                [sslPreBuffer didWrite:bytesReadFromSocket];
6736
 
6737
                                size_t bytesToCopy = MIN(totalBytesLeftToBeRead, bytesReadFromSocket);
6738
 
6739
                                LogVerbose(@"%@: Copying %zu bytes out of sslPreBuffer", THIS_METHOD, bytesToCopy);
6740
 
6741
                                memcpy((uint8_t *)buffer + totalBytesRead, [sslPreBuffer readBuffer], bytesToCopy);
6742
                                [sslPreBuffer didRead:bytesToCopy];
6743
 
6744
                                totalBytesRead += bytesToCopy;
6745
                                totalBytesLeftToBeRead -= bytesToCopy;
6746
 
6747
                                LogVerbose(@"%@: sslPreBuffer.length = %zu", THIS_METHOD, [sslPreBuffer availableBytes]);
6748
                        }
6749
                        else
6750
                        {
6751
                                totalBytesRead += bytesReadFromSocket;
6752
                                totalBytesLeftToBeRead -= bytesReadFromSocket;
6753
                        }
6754
 
6755
                        done = (totalBytesLeftToBeRead == 0);
6756
 
6757
                        if (done) LogVerbose(@"%@: Complete", THIS_METHOD);
6758
                }
6759
        }
6760
 
6761
        *bufferLength = totalBytesRead;
6762
 
6763
        if (done)
6764
                return noErr;
6765
 
6766
        if (socketError)
6767
                return errSSLClosedAbort;
6768
 
6769
        return errSSLWouldBlock;
6770
}
6771
 
6772
- (OSStatus)sslWriteWithBuffer:(const void *)buffer length:(size_t *)bufferLength
6773
{
6774
        if (!(flags & kSocketCanAcceptBytes))
6775
        {
6776
                // Unable to write.
6777
                //
6778
                // Need to wait for writeSource to fire and notify us of
6779
                // available space in the socket's internal write buffer.
6780
 
6781
                [self resumeWriteSource];
6782
 
6783
                *bufferLength = 0;
6784
                return errSSLWouldBlock;
6785
        }
6786
 
6787
        size_t bytesToWrite = *bufferLength;
6788
        size_t bytesWritten = 0;
6789
 
6790
        BOOL done = NO;
6791
        BOOL socketError = NO;
6792
 
6793
        int socketFD = (socket4FD != SOCKET_NULL) ? socket4FD : (socket6FD != SOCKET_NULL) ? socket6FD : socketUN;
6794
 
6795
        ssize_t result = write(socketFD, buffer, bytesToWrite);
6796
 
6797
        if (result < 0)
6798
        {
6799
                if (errno != EWOULDBLOCK)
6800
                {
6801
                        socketError = YES;
6802
                }
6803
 
6804
                flags &= ~kSocketCanAcceptBytes;
6805
        }
6806
        else if (result == 0)
6807
        {
6808
                flags &= ~kSocketCanAcceptBytes;
6809
        }
6810
        else
6811
        {
6812
                bytesWritten = result;
6813
 
6814
                done = (bytesWritten == bytesToWrite);
6815
        }
6816
 
6817
        *bufferLength = bytesWritten;
6818
 
6819
        if (done)
6820
                return noErr;
6821
 
6822
        if (socketError)
6823
                return errSSLClosedAbort;
6824
 
6825
        return errSSLWouldBlock;
6826
}
6827
 
6828
static OSStatus SSLReadFunction(SSLConnectionRef connection, void *data, size_t *dataLength)
6829
{
6830
        GCDAsyncSocket *asyncSocket = (__bridge GCDAsyncSocket *)connection;
6831
 
6832
        NSCAssert(dispatch_get_specific(asyncSocket->IsOnSocketQueueOrTargetQueueKey), @"What the deuce?");
6833
 
6834
        return [asyncSocket sslReadWithBuffer:data length:dataLength];
6835
}
6836
 
6837
static OSStatus SSLWriteFunction(SSLConnectionRef connection, const void *data, size_t *dataLength)
6838
{
6839
        GCDAsyncSocket *asyncSocket = (__bridge GCDAsyncSocket *)connection;
6840
 
6841
        NSCAssert(dispatch_get_specific(asyncSocket->IsOnSocketQueueOrTargetQueueKey), @"What the deuce?");
6842
 
6843
        return [asyncSocket sslWriteWithBuffer:data length:dataLength];
6844
}
6845
 
6846
- (void)ssl_startTLS
6847
{
6848
        LogTrace();
6849
 
6850
        LogVerbose(@"Starting TLS (via SecureTransport)...");
6851
 
6852
        OSStatus status;
6853
 
6854
        GCDAsyncSpecialPacket *tlsPacket = (GCDAsyncSpecialPacket *)currentRead;
6855
        if (tlsPacket == nil) // Code to quiet the analyzer
6856
        {
6857
                NSAssert(NO, @"Logic error");
6858
 
6859
                [self closeWithError:[self otherError:@"Logic error"]];
6860
                return;
6861
        }
6862
        NSDictionary *tlsSettings = tlsPacket->tlsSettings;
6863
 
6864
        // Create SSLContext, and setup IO callbacks and connection ref
6865
 
6866
        NSNumber *isServerNumber = [tlsSettings objectForKey:(__bridge NSString *)kCFStreamSSLIsServer];
6867
        BOOL isServer = [isServerNumber boolValue];
6868
 
6869
        #if TARGET_OS_IPHONE || (__MAC_OS_X_VERSION_MIN_REQUIRED >= 1080)
6870
        {
6871
                if (isServer)
6872
                        sslContext = SSLCreateContext(kCFAllocatorDefault, kSSLServerSide, kSSLStreamType);
6873
                else
6874
                        sslContext = SSLCreateContext(kCFAllocatorDefault, kSSLClientSide, kSSLStreamType);
6875
 
6876
                if (sslContext == NULL)
6877
                {
6878
                        [self closeWithError:[self otherError:@"Error in SSLCreateContext"]];
6879
                        return;
6880
                }
6881
        }
6882
        #else // (__MAC_OS_X_VERSION_MIN_REQUIRED < 1080)
6883
        {
6884
                status = SSLNewContext(isServer, &sslContext);
6885
                if (status != noErr)
6886
                {
6887
                        [self closeWithError:[self otherError:@"Error in SSLNewContext"]];
6888
                        return;
6889
                }
6890
        }
6891
        #endif
6892
 
6893
        status = SSLSetIOFuncs(sslContext, &SSLReadFunction, &SSLWriteFunction);
6894
        if (status != noErr)
6895
        {
6896
                [self closeWithError:[self otherError:@"Error in SSLSetIOFuncs"]];
6897
                return;
6898
        }
6899
 
6900
        status = SSLSetConnection(sslContext, (__bridge SSLConnectionRef)self);
6901
        if (status != noErr)
6902
        {
6903
                [self closeWithError:[self otherError:@"Error in SSLSetConnection"]];
6904
                return;
6905
        }
6906
 
6907
 
6908
        NSNumber *shouldManuallyEvaluateTrust = [tlsSettings objectForKey:GCDAsyncSocketManuallyEvaluateTrust];
6909
        if ([shouldManuallyEvaluateTrust boolValue])
6910
        {
6911
                if (isServer)
6912
                {
6913
                        [self closeWithError:[self otherError:@"Manual trust validation is not supported for server sockets"]];
6914
                        return;
6915
                }
6916
 
6917
                status = SSLSetSessionOption(sslContext, kSSLSessionOptionBreakOnServerAuth, true);
6918
                if (status != noErr)
6919
                {
6920
                        [self closeWithError:[self otherError:@"Error in SSLSetSessionOption"]];
6921
                        return;
6922
                }
6923
 
6924
                #if !TARGET_OS_IPHONE && (__MAC_OS_X_VERSION_MIN_REQUIRED < 1080)
6925
 
6926
                // Note from Apple's documentation:
6927
                //
6928
                // It is only necessary to call SSLSetEnableCertVerify on the Mac prior to OS X 10.8.
6929
                // On OS X 10.8 and later setting kSSLSessionOptionBreakOnServerAuth always disables the
6930
                // built-in trust evaluation. All versions of iOS behave like OS X 10.8 and thus
6931
                // SSLSetEnableCertVerify is not available on that platform at all.
6932
 
6933
                status = SSLSetEnableCertVerify(sslContext, NO);
6934
                if (status != noErr)
6935
                {
6936
                        [self closeWithError:[self otherError:@"Error in SSLSetEnableCertVerify"]];
6937
                        return;
6938
                }
6939
 
6940
                #endif
6941
        }
6942
 
6943
        // Configure SSLContext from given settings
6944
        //
6945
        // Checklist:
6946
        //  1. kCFStreamSSLPeerName
6947
        //  2. kCFStreamSSLCertificates
6948
        //  3. GCDAsyncSocketSSLPeerID
6949
        //  4. GCDAsyncSocketSSLProtocolVersionMin
6950
        //  5. GCDAsyncSocketSSLProtocolVersionMax
6951
        //  6. GCDAsyncSocketSSLSessionOptionFalseStart
6952
        //  7. GCDAsyncSocketSSLSessionOptionSendOneByteRecord
6953
        //  8. GCDAsyncSocketSSLCipherSuites
6954
        //  9. GCDAsyncSocketSSLDiffieHellmanParameters (Mac)
6955
    // 10. GCDAsyncSocketSSLALPN
6956
        //
6957
        // Deprecated (throw error):
6958
        // 10. kCFStreamSSLAllowsAnyRoot
6959
        // 11. kCFStreamSSLAllowsExpiredRoots
6960
        // 12. kCFStreamSSLAllowsExpiredCertificates
6961
        // 13. kCFStreamSSLValidatesCertificateChain
6962
        // 14. kCFStreamSSLLevel
6963
 
6964
        NSObject *value;
6965
 
6966
        // 1. kCFStreamSSLPeerName
6967
 
6968
        value = [tlsSettings objectForKey:(__bridge NSString *)kCFStreamSSLPeerName];
6969
        if ([value isKindOfClass:[NSString class]])
6970
        {
6971
                NSString *peerName = (NSString *)value;
6972
 
6973
                const char *peer = [peerName UTF8String];
6974
                size_t peerLen = strlen(peer);
6975
 
6976
                status = SSLSetPeerDomainName(sslContext, peer, peerLen);
6977
                if (status != noErr)
6978
                {
6979
                        [self closeWithError:[self otherError:@"Error in SSLSetPeerDomainName"]];
6980
                        return;
6981
                }
6982
        }
6983
        else if (value)
6984
        {
6985
                NSAssert(NO, @"Invalid value for kCFStreamSSLPeerName. Value must be of type NSString.");
6986
 
6987
                [self closeWithError:[self otherError:@"Invalid value for kCFStreamSSLPeerName."]];
6988
                return;
6989
        }
6990
 
6991
        // 2. kCFStreamSSLCertificates
6992
 
6993
        value = [tlsSettings objectForKey:(__bridge NSString *)kCFStreamSSLCertificates];
6994
        if ([value isKindOfClass:[NSArray class]])
6995
        {
6996
                NSArray *certs = (NSArray *)value;
6997
 
6998
                status = SSLSetCertificate(sslContext, (__bridge CFArrayRef)certs);
6999
                if (status != noErr)
7000
                {
7001
                        [self closeWithError:[self otherError:@"Error in SSLSetCertificate"]];
7002
                        return;
7003
                }
7004
        }
7005
        else if (value)
7006
        {
7007
                NSAssert(NO, @"Invalid value for kCFStreamSSLCertificates. Value must be of type NSArray.");
7008
 
7009
                [self closeWithError:[self otherError:@"Invalid value for kCFStreamSSLCertificates."]];
7010
                return;
7011
        }
7012
 
7013
        // 3. GCDAsyncSocketSSLPeerID
7014
 
7015
        value = [tlsSettings objectForKey:GCDAsyncSocketSSLPeerID];
7016
        if ([value isKindOfClass:[NSData class]])
7017
        {
7018
                NSData *peerIdData = (NSData *)value;
7019
 
7020
                status = SSLSetPeerID(sslContext, [peerIdData bytes], [peerIdData length]);
7021
                if (status != noErr)
7022
                {
7023
                        [self closeWithError:[self otherError:@"Error in SSLSetPeerID"]];
7024
                        return;
7025
                }
7026
        }
7027
        else if (value)
7028
        {
7029
                NSAssert(NO, @"Invalid value for GCDAsyncSocketSSLPeerID. Value must be of type NSData."
7030
                             @" (You can convert strings to data using a method like"
7031
                             @" [string dataUsingEncoding:NSUTF8StringEncoding])");
7032
 
7033
                [self closeWithError:[self otherError:@"Invalid value for GCDAsyncSocketSSLPeerID."]];
7034
                return;
7035
        }
7036
 
7037
        // 4. GCDAsyncSocketSSLProtocolVersionMin
7038
 
7039
        value = [tlsSettings objectForKey:GCDAsyncSocketSSLProtocolVersionMin];
7040
        if ([value isKindOfClass:[NSNumber class]])
7041
        {
7042
                SSLProtocol minProtocol = (SSLProtocol)[(NSNumber *)value intValue];
7043
                if (minProtocol != kSSLProtocolUnknown)
7044
                {
7045
                        status = SSLSetProtocolVersionMin(sslContext, minProtocol);
7046
                        if (status != noErr)
7047
                        {
7048
                                [self closeWithError:[self otherError:@"Error in SSLSetProtocolVersionMin"]];
7049
                                return;
7050
                        }
7051
                }
7052
        }
7053
        else if (value)
7054
        {
7055
                NSAssert(NO, @"Invalid value for GCDAsyncSocketSSLProtocolVersionMin. Value must be of type NSNumber.");
7056
 
7057
                [self closeWithError:[self otherError:@"Invalid value for GCDAsyncSocketSSLProtocolVersionMin."]];
7058
                return;
7059
        }
7060
 
7061
        // 5. GCDAsyncSocketSSLProtocolVersionMax
7062
 
7063
        value = [tlsSettings objectForKey:GCDAsyncSocketSSLProtocolVersionMax];
7064
        if ([value isKindOfClass:[NSNumber class]])
7065
        {
7066
                SSLProtocol maxProtocol = (SSLProtocol)[(NSNumber *)value intValue];
7067
                if (maxProtocol != kSSLProtocolUnknown)
7068
                {
7069
                        status = SSLSetProtocolVersionMax(sslContext, maxProtocol);
7070
                        if (status != noErr)
7071
                        {
7072
                                [self closeWithError:[self otherError:@"Error in SSLSetProtocolVersionMax"]];
7073
                                return;
7074
                        }
7075
                }
7076
        }
7077
        else if (value)
7078
        {
7079
                NSAssert(NO, @"Invalid value for GCDAsyncSocketSSLProtocolVersionMax. Value must be of type NSNumber.");
7080
 
7081
                [self closeWithError:[self otherError:@"Invalid value for GCDAsyncSocketSSLProtocolVersionMax."]];
7082
                return;
7083
        }
7084
 
7085
        // 6. GCDAsyncSocketSSLSessionOptionFalseStart
7086
 
7087
        value = [tlsSettings objectForKey:GCDAsyncSocketSSLSessionOptionFalseStart];
7088
        if ([value isKindOfClass:[NSNumber class]])
7089
        {
7090
                NSNumber *falseStart = (NSNumber *)value;
7091
                status = SSLSetSessionOption(sslContext, kSSLSessionOptionFalseStart, [falseStart boolValue]);
7092
                if (status != noErr)
7093
                {
7094
                        [self closeWithError:[self otherError:@"Error in SSLSetSessionOption (kSSLSessionOptionFalseStart)"]];
7095
                        return;
7096
                }
7097
        }
7098
        else if (value)
7099
        {
7100
                NSAssert(NO, @"Invalid value for GCDAsyncSocketSSLSessionOptionFalseStart. Value must be of type NSNumber.");
7101
 
7102
                [self closeWithError:[self otherError:@"Invalid value for GCDAsyncSocketSSLSessionOptionFalseStart."]];
7103
                return;
7104
        }
7105
 
7106
        // 7. GCDAsyncSocketSSLSessionOptionSendOneByteRecord
7107
 
7108
        value = [tlsSettings objectForKey:GCDAsyncSocketSSLSessionOptionSendOneByteRecord];
7109
        if ([value isKindOfClass:[NSNumber class]])
7110
        {
7111
                NSNumber *oneByteRecord = (NSNumber *)value;
7112
                status = SSLSetSessionOption(sslContext, kSSLSessionOptionSendOneByteRecord, [oneByteRecord boolValue]);
7113
                if (status != noErr)
7114
                {
7115
                        [self closeWithError:
7116
                          [self otherError:@"Error in SSLSetSessionOption (kSSLSessionOptionSendOneByteRecord)"]];
7117
                        return;
7118
                }
7119
        }
7120
        else if (value)
7121
        {
7122
                NSAssert(NO, @"Invalid value for GCDAsyncSocketSSLSessionOptionSendOneByteRecord."
7123
                             @" Value must be of type NSNumber.");
7124
 
7125
                [self closeWithError:[self otherError:@"Invalid value for GCDAsyncSocketSSLSessionOptionSendOneByteRecord."]];
7126
                return;
7127
        }
7128
 
7129
        // 8. GCDAsyncSocketSSLCipherSuites
7130
 
7131
        value = [tlsSettings objectForKey:GCDAsyncSocketSSLCipherSuites];
7132
        if ([value isKindOfClass:[NSArray class]])
7133
        {
7134
                NSArray *cipherSuites = (NSArray *)value;
7135
                NSUInteger numberCiphers = [cipherSuites count];
7136
                SSLCipherSuite ciphers[numberCiphers];
7137
 
7138
                NSUInteger cipherIndex;
7139
                for (cipherIndex = 0; cipherIndex < numberCiphers; cipherIndex++)
7140
                {
7141
                        NSNumber *cipherObject = [cipherSuites objectAtIndex:cipherIndex];
7142
                        ciphers[cipherIndex] = (SSLCipherSuite)[cipherObject unsignedIntValue];
7143
                }
7144
 
7145
                status = SSLSetEnabledCiphers(sslContext, ciphers, numberCiphers);
7146
                if (status != noErr)
7147
                {
7148
                        [self closeWithError:[self otherError:@"Error in SSLSetEnabledCiphers"]];
7149
                        return;
7150
                }
7151
        }
7152
        else if (value)
7153
        {
7154
                NSAssert(NO, @"Invalid value for GCDAsyncSocketSSLCipherSuites. Value must be of type NSArray.");
7155
 
7156
                [self closeWithError:[self otherError:@"Invalid value for GCDAsyncSocketSSLCipherSuites."]];
7157
                return;
7158
        }
7159
 
7160
        // 9. GCDAsyncSocketSSLDiffieHellmanParameters
7161
 
7162
        #if !TARGET_OS_IPHONE
7163
        value = [tlsSettings objectForKey:GCDAsyncSocketSSLDiffieHellmanParameters];
7164
        if ([value isKindOfClass:[NSData class]])
7165
        {
7166
                NSData *diffieHellmanData = (NSData *)value;
7167
 
7168
                status = SSLSetDiffieHellmanParams(sslContext, [diffieHellmanData bytes], [diffieHellmanData length]);
7169
                if (status != noErr)
7170
                {
7171
                        [self closeWithError:[self otherError:@"Error in SSLSetDiffieHellmanParams"]];
7172
                        return;
7173
                }
7174
        }
7175
        else if (value)
7176
        {
7177
                NSAssert(NO, @"Invalid value for GCDAsyncSocketSSLDiffieHellmanParameters. Value must be of type NSData.");
7178
 
7179
                [self closeWithError:[self otherError:@"Invalid value for GCDAsyncSocketSSLDiffieHellmanParameters."]];
7180
                return;
7181
        }
7182
        #endif
7183
 
7184
    // 10. kCFStreamSSLCertificates
7185
    value = [tlsSettings objectForKey:GCDAsyncSocketSSLALPN];
7186
    if ([value isKindOfClass:[NSArray class]])
7187
    {
7188
        if (@available(iOS 11.0, macOS 10.13, tvOS 11.0, *))
7189
        {
7190
            CFArrayRef protocols = (__bridge CFArrayRef)((NSArray *) value);
7191
            status = SSLSetALPNProtocols(sslContext, protocols);
7192
            if (status != noErr)
7193
            {
7194
                [self closeWithError:[self otherError:@"Error in SSLSetALPNProtocols"]];
7195
                return;
7196
            }
7197
        }
7198
        else
7199
        {
7200
            NSAssert(NO, @"Security option unavailable - GCDAsyncSocketSSLALPN"
7201
                     @" - iOS 11.0, macOS 10.13 required");
7202
            [self closeWithError:[self otherError:@"Security option unavailable - GCDAsyncSocketSSLALPN"]];
7203
        }
7204
    }
7205
    else if (value)
7206
    {
7207
        NSAssert(NO, @"Invalid value for GCDAsyncSocketSSLALPN. Value must be of type NSArray.");
7208
 
7209
        [self closeWithError:[self otherError:@"Invalid value for GCDAsyncSocketSSLALPN."]];
7210
        return;
7211
    }
7212
 
7213
        // DEPRECATED checks
7214
 
7215
        // 10. kCFStreamSSLAllowsAnyRoot
7216
 
7217
        #pragma clang diagnostic push
7218
        #pragma clang diagnostic ignored "-Wdeprecated-declarations"
7219
        value = [tlsSettings objectForKey:(__bridge NSString *)kCFStreamSSLAllowsAnyRoot];
7220
        #pragma clang diagnostic pop
7221
        if (value)
7222
        {
7223
                NSAssert(NO, @"Security option unavailable - kCFStreamSSLAllowsAnyRoot"
7224
                             @" - You must use manual trust evaluation");
7225
 
7226
                [self closeWithError:[self otherError:@"Security option unavailable - kCFStreamSSLAllowsAnyRoot"]];
7227
                return;
7228
        }
7229
 
7230
        // 11. kCFStreamSSLAllowsExpiredRoots
7231
 
7232
        #pragma clang diagnostic push
7233
        #pragma clang diagnostic ignored "-Wdeprecated-declarations"
7234
        value = [tlsSettings objectForKey:(__bridge NSString *)kCFStreamSSLAllowsExpiredRoots];
7235
        #pragma clang diagnostic pop
7236
        if (value)
7237
        {
7238
                NSAssert(NO, @"Security option unavailable - kCFStreamSSLAllowsExpiredRoots"
7239
                             @" - You must use manual trust evaluation");
7240
 
7241
                [self closeWithError:[self otherError:@"Security option unavailable - kCFStreamSSLAllowsExpiredRoots"]];
7242
                return;
7243
        }
7244
 
7245
        // 12. kCFStreamSSLValidatesCertificateChain
7246
 
7247
        #pragma clang diagnostic push
7248
        #pragma clang diagnostic ignored "-Wdeprecated-declarations"
7249
        value = [tlsSettings objectForKey:(__bridge NSString *)kCFStreamSSLValidatesCertificateChain];
7250
        #pragma clang diagnostic pop
7251
        if (value)
7252
        {
7253
                NSAssert(NO, @"Security option unavailable - kCFStreamSSLValidatesCertificateChain"
7254
                             @" - You must use manual trust evaluation");
7255
 
7256
                [self closeWithError:[self otherError:@"Security option unavailable - kCFStreamSSLValidatesCertificateChain"]];
7257
                return;
7258
        }
7259
 
7260
        // 13. kCFStreamSSLAllowsExpiredCertificates
7261
 
7262
        #pragma clang diagnostic push
7263
        #pragma clang diagnostic ignored "-Wdeprecated-declarations"
7264
        value = [tlsSettings objectForKey:(__bridge NSString *)kCFStreamSSLAllowsExpiredCertificates];
7265
        #pragma clang diagnostic pop
7266
        if (value)
7267
        {
7268
                NSAssert(NO, @"Security option unavailable - kCFStreamSSLAllowsExpiredCertificates"
7269
                             @" - You must use manual trust evaluation");
7270
 
7271
                [self closeWithError:[self otherError:@"Security option unavailable - kCFStreamSSLAllowsExpiredCertificates"]];
7272
                return;
7273
        }
7274
 
7275
        // 14. kCFStreamSSLLevel
7276
 
7277
        #pragma clang diagnostic push
7278
        #pragma clang diagnostic ignored "-Wdeprecated-declarations"
7279
        value = [tlsSettings objectForKey:(__bridge NSString *)kCFStreamSSLLevel];
7280
        #pragma clang diagnostic pop
7281
        if (value)
7282
        {
7283
                NSAssert(NO, @"Security option unavailable - kCFStreamSSLLevel"
7284
                             @" - You must use GCDAsyncSocketSSLProtocolVersionMin & GCDAsyncSocketSSLProtocolVersionMax");
7285
 
7286
                [self closeWithError:[self otherError:@"Security option unavailable - kCFStreamSSLLevel"]];
7287
                return;
7288
        }
7289
 
7290
        // Setup the sslPreBuffer
7291
        //
7292
        // Any data in the preBuffer needs to be moved into the sslPreBuffer,
7293
        // as this data is now part of the secure read stream.
7294
 
7295
        sslPreBuffer = [[GCDAsyncSocketPreBuffer alloc] initWithCapacity:(1024 * 4)];
7296
 
7297
        size_t preBufferLength  = [preBuffer availableBytes];
7298
 
7299
        if (preBufferLength > 0)
7300
        {
7301
                [sslPreBuffer ensureCapacityForWrite:preBufferLength];
7302
 
7303
                memcpy([sslPreBuffer writeBuffer], [preBuffer readBuffer], preBufferLength);
7304
                [preBuffer didRead:preBufferLength];
7305
                [sslPreBuffer didWrite:preBufferLength];
7306
        }
7307
 
7308
        sslErrCode = lastSSLHandshakeError = noErr;
7309
 
7310
        // Start the SSL Handshake process
7311
 
7312
        [self ssl_continueSSLHandshake];
7313
}
7314
 
7315
- (void)ssl_continueSSLHandshake
7316
{
7317
        LogTrace();
7318
 
7319
        // If the return value is noErr, the session is ready for normal secure communication.
7320
        // If the return value is errSSLWouldBlock, the SSLHandshake function must be called again.
7321
        // If the return value is errSSLServerAuthCompleted, we ask delegate if we should trust the
7322
        // server and then call SSLHandshake again to resume the handshake or close the connection
7323
        // errSSLPeerBadCert SSL error.
7324
        // Otherwise, the return value indicates an error code.
7325
 
7326
        OSStatus status = SSLHandshake(sslContext);
7327
        lastSSLHandshakeError = status;
7328
 
7329
        if (status == noErr)
7330
        {
7331
                LogVerbose(@"SSLHandshake complete");
7332
 
7333
                flags &= ~kStartingReadTLS;
7334
                flags &= ~kStartingWriteTLS;
7335
 
7336
                flags |=  kSocketSecure;
7337
 
7338
                __strong id<GCDAsyncSocketDelegate> theDelegate = delegate;
7339
 
7340
                if (delegateQueue && [theDelegate respondsToSelector:@selector(socketDidSecure:)])
7341
                {
7342
                        dispatch_async(delegateQueue, ^{ @autoreleasepool {
7343
 
7344
                                [theDelegate socketDidSecure:self];
7345
                        }});
7346
                }
7347
 
7348
                [self endCurrentRead];
7349
                [self endCurrentWrite];
7350
 
7351
                [self maybeDequeueRead];
7352
                [self maybeDequeueWrite];
7353
        }
7354
        else if (status == errSSLPeerAuthCompleted)
7355
        {
7356
                LogVerbose(@"SSLHandshake peerAuthCompleted - awaiting delegate approval");
7357
 
7358
                __block SecTrustRef trust = NULL;
7359
                status = SSLCopyPeerTrust(sslContext, &trust);
7360
                if (status != noErr)
7361
                {
7362
                        [self closeWithError:[self sslError:status]];
7363
                        return;
7364
                }
7365
 
7366
                int aStateIndex = stateIndex;
7367
                dispatch_queue_t theSocketQueue = socketQueue;
7368
 
7369
                __weak GCDAsyncSocket *weakSelf = self;
7370
 
7371
                void (^comletionHandler)(BOOL) = ^(BOOL shouldTrust){ @autoreleasepool {
7372
                #pragma clang diagnostic push
7373
                #pragma clang diagnostic warning "-Wimplicit-retain-self"
7374
 
7375
                        dispatch_async(theSocketQueue, ^{ @autoreleasepool {
7376
 
7377
                                if (trust) {
7378
                                        CFRelease(trust);
7379
                                        trust = NULL;
7380
                                }
7381
 
7382
                                __strong GCDAsyncSocket *strongSelf = weakSelf;
7383
                                if (strongSelf)
7384
                                {
7385
                                        [strongSelf ssl_shouldTrustPeer:shouldTrust stateIndex:aStateIndex];
7386
                                }
7387
                        }});
7388
 
7389
                #pragma clang diagnostic pop
7390
                }};
7391
 
7392
                __strong id<GCDAsyncSocketDelegate> theDelegate = delegate;
7393
 
7394
                if (delegateQueue && [theDelegate respondsToSelector:@selector(socket:didReceiveTrust:completionHandler:)])
7395
                {
7396
                        dispatch_async(delegateQueue, ^{ @autoreleasepool {
7397
 
7398
                                [theDelegate socket:self didReceiveTrust:trust completionHandler:comletionHandler];
7399
                        }});
7400
                }
7401
                else
7402
                {
7403
                        if (trust) {
7404
                                CFRelease(trust);
7405
                                trust = NULL;
7406
                        }
7407
 
7408
                        NSString *msg = @"GCDAsyncSocketManuallyEvaluateTrust specified in tlsSettings,"
7409
                                        @" but delegate doesn't implement socket:shouldTrustPeer:";
7410
 
7411
                        [self closeWithError:[self otherError:msg]];
7412
                        return;
7413
                }
7414
        }
7415
        else if (status == errSSLWouldBlock)
7416
        {
7417
                LogVerbose(@"SSLHandshake continues...");
7418
 
7419
                // Handshake continues...
7420
                //
7421
                // This method will be called again from doReadData or doWriteData.
7422
        }
7423
        else
7424
        {
7425
                [self closeWithError:[self sslError:status]];
7426
        }
7427
}
7428
 
7429
- (void)ssl_shouldTrustPeer:(BOOL)shouldTrust stateIndex:(int)aStateIndex
7430
{
7431
        LogTrace();
7432
 
7433
        if (aStateIndex != stateIndex)
7434
        {
7435
                LogInfo(@"Ignoring ssl_shouldTrustPeer - invalid state (maybe disconnected)");
7436
 
7437
                // One of the following is true
7438
                // - the socket was disconnected
7439
                // - the startTLS operation timed out
7440
                // - the completionHandler was already invoked once
7441
 
7442
                return;
7443
        }
7444
 
7445
        // Increment stateIndex to ensure completionHandler can only be called once.
7446
        stateIndex++;
7447
 
7448
        if (shouldTrust)
7449
        {
7450
        NSAssert(lastSSLHandshakeError == errSSLPeerAuthCompleted, @"ssl_shouldTrustPeer called when last error is %d and not errSSLPeerAuthCompleted", (int)lastSSLHandshakeError);
7451
                [self ssl_continueSSLHandshake];
7452
        }
7453
        else
7454
        {
7455
                [self closeWithError:[self sslError:errSSLPeerBadCert]];
7456
        }
7457
}
7458
 
7459
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
7460
#pragma mark Security via CFStream
7461
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
7462
 
7463
#if TARGET_OS_IPHONE
7464
 
7465
- (void)cf_finishSSLHandshake
7466
{
7467
        LogTrace();
7468
 
7469
        if ((flags & kStartingReadTLS) && (flags & kStartingWriteTLS))
7470
        {
7471
                flags &= ~kStartingReadTLS;
7472
                flags &= ~kStartingWriteTLS;
7473
 
7474
                flags |= kSocketSecure;
7475
 
7476
                __strong id<GCDAsyncSocketDelegate> theDelegate = delegate;
7477
 
7478
                if (delegateQueue && [theDelegate respondsToSelector:@selector(socketDidSecure:)])
7479
                {
7480
                        dispatch_async(delegateQueue, ^{ @autoreleasepool {
7481
 
7482
                                [theDelegate socketDidSecure:self];
7483
                        }});
7484
                }
7485
 
7486
                [self endCurrentRead];
7487
                [self endCurrentWrite];
7488
 
7489
                [self maybeDequeueRead];
7490
                [self maybeDequeueWrite];
7491
        }
7492
}
7493
 
7494
- (void)cf_abortSSLHandshake:(NSError *)error
7495
{
7496
        LogTrace();
7497
 
7498
        if ((flags & kStartingReadTLS) && (flags & kStartingWriteTLS))
7499
        {
7500
                flags &= ~kStartingReadTLS;
7501
                flags &= ~kStartingWriteTLS;
7502
 
7503
                [self closeWithError:error];
7504
        }
7505
}
7506
 
7507
- (void)cf_startTLS
7508
{
7509
        LogTrace();
7510
 
7511
        LogVerbose(@"Starting TLS (via CFStream)...");
7512
 
7513
        if ([preBuffer availableBytes] > 0)
7514
        {
7515
                NSString *msg = @"Invalid TLS transition. Handshake has already been read from socket.";
7516
 
7517
                [self closeWithError:[self otherError:msg]];
7518
                return;
7519
        }
7520
 
7521
        [self suspendReadSource];
7522
        [self suspendWriteSource];
7523
 
7524
        socketFDBytesAvailable = 0;
7525
        flags &= ~kSocketCanAcceptBytes;
7526
        flags &= ~kSecureSocketHasBytesAvailable;
7527
 
7528
        flags |=  kUsingCFStreamForTLS;
7529
 
7530
        if (![self createReadAndWriteStream])
7531
        {
7532
                [self closeWithError:[self otherError:@"Error in CFStreamCreatePairWithSocket"]];
7533
                return;
7534
        }
7535
 
7536
        if (![self registerForStreamCallbacksIncludingReadWrite:YES])
7537
        {
7538
                [self closeWithError:[self otherError:@"Error in CFStreamSetClient"]];
7539
                return;
7540
        }
7541
 
7542
        if (![self addStreamsToRunLoop])
7543
        {
7544
                [self closeWithError:[self otherError:@"Error in CFStreamScheduleWithRunLoop"]];
7545
                return;
7546
        }
7547
 
7548
        NSAssert([currentRead isKindOfClass:[GCDAsyncSpecialPacket class]], @"Invalid read packet for startTLS");
7549
        NSAssert([currentWrite isKindOfClass:[GCDAsyncSpecialPacket class]], @"Invalid write packet for startTLS");
7550
 
7551
        GCDAsyncSpecialPacket *tlsPacket = (GCDAsyncSpecialPacket *)currentRead;
7552
        CFDictionaryRef tlsSettings = (__bridge CFDictionaryRef)tlsPacket->tlsSettings;
7553
 
7554
        // Getting an error concerning kCFStreamPropertySSLSettings ?
7555
        // You need to add the CFNetwork framework to your iOS application.
7556
 
7557
        BOOL r1 = CFReadStreamSetProperty(readStream, kCFStreamPropertySSLSettings, tlsSettings);
7558
        BOOL r2 = CFWriteStreamSetProperty(writeStream, kCFStreamPropertySSLSettings, tlsSettings);
7559
 
7560
        // For some reason, starting around the time of iOS 4.3,
7561
        // the first call to set the kCFStreamPropertySSLSettings will return true,
7562
        // but the second will return false.
7563
        //
7564
        // Order doesn't seem to matter.
7565
        // So you could call CFReadStreamSetProperty and then CFWriteStreamSetProperty, or you could reverse the order.
7566
        // Either way, the first call will return true, and the second returns false.
7567
        //
7568
        // Interestingly, this doesn't seem to affect anything.
7569
        // Which is not altogether unusual, as the documentation seems to suggest that (for many settings)
7570
        // setting it on one side of the stream automatically sets it for the other side of the stream.
7571
        //
7572
        // Although there isn't anything in the documentation to suggest that the second attempt would fail.
7573
        //
7574
        // Furthermore, this only seems to affect streams that are negotiating a security upgrade.
7575
        // In other words, the socket gets connected, there is some back-and-forth communication over the unsecure
7576
        // connection, and then a startTLS is issued.
7577
        // So this mostly affects newer protocols (XMPP, IMAP) as opposed to older protocols (HTTPS).
7578
 
7579
        if (!r1 && !r2) // Yes, the && is correct - workaround for apple bug.
7580
        {
7581
                [self closeWithError:[self otherError:@"Error in CFStreamSetProperty"]];
7582
                return;
7583
        }
7584
 
7585
        if (![self openStreams])
7586
        {
7587
                [self closeWithError:[self otherError:@"Error in CFStreamOpen"]];
7588
                return;
7589
        }
7590
 
7591
        LogVerbose(@"Waiting for SSL Handshake to complete...");
7592
}
7593
 
7594
#endif
7595
 
7596
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
7597
#pragma mark CFStream
7598
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
7599
 
7600
#if TARGET_OS_IPHONE
7601
 
7602
+ (void)ignore:(id)_
7603
{}
7604
 
7605
+ (void)startCFStreamThreadIfNeeded
7606
{
7607
        LogTrace();
7608
 
7609
        static dispatch_once_t predicate;
7610
        dispatch_once(&predicate, ^{
7611
 
7612
                cfstreamThreadRetainCount = 0;
7613
                cfstreamThreadSetupQueue = dispatch_queue_create("GCDAsyncSocket-CFStreamThreadSetup", DISPATCH_QUEUE_SERIAL);
7614
        });
7615
 
7616
        dispatch_sync(cfstreamThreadSetupQueue, ^{ @autoreleasepool {
7617
 
7618
                if (++cfstreamThreadRetainCount == 1)
7619
                {
7620
                        cfstreamThread = [[NSThread alloc] initWithTarget:self
7621
                                                                 selector:@selector(cfstreamThread:)
7622
                                                                   object:nil];
7623
                        [cfstreamThread start];
7624
                }
7625
        }});
7626
}
7627
 
7628
+ (void)stopCFStreamThreadIfNeeded
7629
{
7630
        LogTrace();
7631
 
7632
        // The creation of the cfstreamThread is relatively expensive.
7633
        // So we'd like to keep it available for recycling.
7634
        // However, there's a tradeoff here, because it shouldn't remain alive forever.
7635
        // So what we're going to do is use a little delay before taking it down.
7636
        // This way it can be reused properly in situations where multiple sockets are continually in flux.
7637
 
7638
        int delayInSeconds = 30;
7639
        dispatch_time_t when = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
7640
        dispatch_after(when, cfstreamThreadSetupQueue, ^{ @autoreleasepool {
7641
        #pragma clang diagnostic push
7642
        #pragma clang diagnostic warning "-Wimplicit-retain-self"
7643
 
7644
                if (cfstreamThreadRetainCount == 0)
7645
                {
7646
                        LogWarn(@"Logic error concerning cfstreamThread start / stop");
7647
                        return_from_block;
7648
                }
7649
 
7650
                if (--cfstreamThreadRetainCount == 0)
7651
                {
7652
                        [cfstreamThread cancel]; // set isCancelled flag
7653
 
7654
                        // wake up the thread
7655
            [[self class] performSelector:@selector(ignore:)
7656
                                 onThread:cfstreamThread
7657
                               withObject:[NSNull null]
7658
                            waitUntilDone:NO];
7659
 
7660
                        cfstreamThread = nil;
7661
                }
7662
 
7663
        #pragma clang diagnostic pop
7664
        }});
7665
}
7666
 
7667
+ (void)cfstreamThread:(id)unused { @autoreleasepool
7668
{
7669
        [[NSThread currentThread] setName:GCDAsyncSocketThreadName];
7670
 
7671
        LogInfo(@"CFStreamThread: Started");
7672
 
7673
        // We can't run the run loop unless it has an associated input source or a timer.
7674
        // So we'll just create a timer that will never fire - unless the server runs for decades.
7675
        [NSTimer scheduledTimerWithTimeInterval:[[NSDate distantFuture] timeIntervalSinceNow]
7676
                                         target:self
7677
                                       selector:@selector(ignore:)
7678
                                       userInfo:nil
7679
                                        repeats:YES];
7680
 
7681
        NSThread *currentThread = [NSThread currentThread];
7682
        NSRunLoop *currentRunLoop = [NSRunLoop currentRunLoop];
7683
 
7684
        BOOL isCancelled = [currentThread isCancelled];
7685
 
7686
        while (!isCancelled && [currentRunLoop runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]])
7687
        {
7688
                isCancelled = [currentThread isCancelled];
7689
        }
7690
 
7691
        LogInfo(@"CFStreamThread: Stopped");
7692
}}
7693
 
7694
+ (void)scheduleCFStreams:(GCDAsyncSocket *)asyncSocket
7695
{
7696
        LogTrace();
7697
        NSAssert([NSThread currentThread] == cfstreamThread, @"Invoked on wrong thread");
7698
 
7699
        CFRunLoopRef runLoop = CFRunLoopGetCurrent();
7700
 
7701
        if (asyncSocket->readStream)
7702
                CFReadStreamScheduleWithRunLoop(asyncSocket->readStream, runLoop, kCFRunLoopDefaultMode);
7703
 
7704
        if (asyncSocket->writeStream)
7705
                CFWriteStreamScheduleWithRunLoop(asyncSocket->writeStream, runLoop, kCFRunLoopDefaultMode);
7706
}
7707
 
7708
+ (void)unscheduleCFStreams:(GCDAsyncSocket *)asyncSocket
7709
{
7710
        LogTrace();
7711
        NSAssert([NSThread currentThread] == cfstreamThread, @"Invoked on wrong thread");
7712
 
7713
        CFRunLoopRef runLoop = CFRunLoopGetCurrent();
7714
 
7715
        if (asyncSocket->readStream)
7716
                CFReadStreamUnscheduleFromRunLoop(asyncSocket->readStream, runLoop, kCFRunLoopDefaultMode);
7717
 
7718
        if (asyncSocket->writeStream)
7719
                CFWriteStreamUnscheduleFromRunLoop(asyncSocket->writeStream, runLoop, kCFRunLoopDefaultMode);
7720
}
7721
 
7722
static void CFReadStreamCallback (CFReadStreamRef stream, CFStreamEventType type, void *pInfo)
7723
{
7724
        GCDAsyncSocket *asyncSocket = (__bridge GCDAsyncSocket *)pInfo;
7725
 
7726
        switch(type)
7727
        {
7728
                case kCFStreamEventHasBytesAvailable:
7729
                {
7730
                        dispatch_async(asyncSocket->socketQueue, ^{ @autoreleasepool {
7731
 
7732
                                LogCVerbose(@"CFReadStreamCallback - HasBytesAvailable");
7733
 
7734
                                if (asyncSocket->readStream != stream)
7735
                                        return_from_block;
7736
 
7737
                                if ((asyncSocket->flags & kStartingReadTLS) && (asyncSocket->flags & kStartingWriteTLS))
7738
                                {
7739
                                        // If we set kCFStreamPropertySSLSettings before we opened the streams, this might be a lie.
7740
                                        // (A callback related to the tcp stream, but not to the SSL layer).
7741
 
7742
                                        if (CFReadStreamHasBytesAvailable(asyncSocket->readStream))
7743
                                        {
7744
                                                asyncSocket->flags |= kSecureSocketHasBytesAvailable;
7745
                                                [asyncSocket cf_finishSSLHandshake];
7746
                                        }
7747
                                }
7748
                                else
7749
                                {
7750
                                        asyncSocket->flags |= kSecureSocketHasBytesAvailable;
7751
                                        [asyncSocket doReadData];
7752
                                }
7753
                        }});
7754
 
7755
                        break;
7756
                }
7757
                default:
7758
                {
7759
                        NSError *error = (__bridge_transfer  NSError *)CFReadStreamCopyError(stream);
7760
 
7761
                        if (error == nil && type == kCFStreamEventEndEncountered)
7762
                        {
7763
                                error = [asyncSocket connectionClosedError];
7764
                        }
7765
 
7766
                        dispatch_async(asyncSocket->socketQueue, ^{ @autoreleasepool {
7767
 
7768
                                LogCVerbose(@"CFReadStreamCallback - Other");
7769
 
7770
                                if (asyncSocket->readStream != stream)
7771
                                        return_from_block;
7772
 
7773
                                if ((asyncSocket->flags & kStartingReadTLS) && (asyncSocket->flags & kStartingWriteTLS))
7774
                                {
7775
                                        [asyncSocket cf_abortSSLHandshake:error];
7776
                                }
7777
                                else
7778
                                {
7779
                                        [asyncSocket closeWithError:error];
7780
                                }
7781
                        }});
7782
 
7783
                        break;
7784
                }
7785
        }
7786
 
7787
}
7788
 
7789
static void CFWriteStreamCallback (CFWriteStreamRef stream, CFStreamEventType type, void *pInfo)
7790
{
7791
        GCDAsyncSocket *asyncSocket = (__bridge GCDAsyncSocket *)pInfo;
7792
 
7793
        switch(type)
7794
        {
7795
                case kCFStreamEventCanAcceptBytes:
7796
                {
7797
                        dispatch_async(asyncSocket->socketQueue, ^{ @autoreleasepool {
7798
 
7799
                                LogCVerbose(@"CFWriteStreamCallback - CanAcceptBytes");
7800
 
7801
                                if (asyncSocket->writeStream != stream)
7802
                                        return_from_block;
7803
 
7804
                                if ((asyncSocket->flags & kStartingReadTLS) && (asyncSocket->flags & kStartingWriteTLS))
7805
                                {
7806
                                        // If we set kCFStreamPropertySSLSettings before we opened the streams, this might be a lie.
7807
                                        // (A callback related to the tcp stream, but not to the SSL layer).
7808
 
7809
                                        if (CFWriteStreamCanAcceptBytes(asyncSocket->writeStream))
7810
                                        {
7811
                                                asyncSocket->flags |= kSocketCanAcceptBytes;
7812
                                                [asyncSocket cf_finishSSLHandshake];
7813
                                        }
7814
                                }
7815
                                else
7816
                                {
7817
                                        asyncSocket->flags |= kSocketCanAcceptBytes;
7818
                                        [asyncSocket doWriteData];
7819
                                }
7820
                        }});
7821
 
7822
                        break;
7823
                }
7824
                default:
7825
                {
7826
                        NSError *error = (__bridge_transfer NSError *)CFWriteStreamCopyError(stream);
7827
 
7828
                        if (error == nil && type == kCFStreamEventEndEncountered)
7829
                        {
7830
                                error = [asyncSocket connectionClosedError];
7831
                        }
7832
 
7833
                        dispatch_async(asyncSocket->socketQueue, ^{ @autoreleasepool {
7834
 
7835
                                LogCVerbose(@"CFWriteStreamCallback - Other");
7836
 
7837
                                if (asyncSocket->writeStream != stream)
7838
                                        return_from_block;
7839
 
7840
                                if ((asyncSocket->flags & kStartingReadTLS) && (asyncSocket->flags & kStartingWriteTLS))
7841
                                {
7842
                                        [asyncSocket cf_abortSSLHandshake:error];
7843
                                }
7844
                                else
7845
                                {
7846
                                        [asyncSocket closeWithError:error];
7847
                                }
7848
                        }});
7849
 
7850
                        break;
7851
                }
7852
        }
7853
 
7854
}
7855
 
7856
- (BOOL)createReadAndWriteStream
7857
{
7858
        LogTrace();
7859
 
7860
        NSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @"Must be dispatched on socketQueue");
7861
 
7862
 
7863
        if (readStream || writeStream)
7864
        {
7865
                // Streams already created
7866
                return YES;
7867
        }
7868
 
7869
        int socketFD = (socket4FD != SOCKET_NULL) ? socket4FD : (socket6FD != SOCKET_NULL) ? socket6FD : socketUN;
7870
 
7871
        if (socketFD == SOCKET_NULL)
7872
        {
7873
                // Cannot create streams without a file descriptor
7874
                return NO;
7875
        }
7876
 
7877
        if (![self isConnected])
7878
        {
7879
                // Cannot create streams until file descriptor is connected
7880
                return NO;
7881
        }
7882
 
7883
        LogVerbose(@"Creating read and write stream...");
7884
 
7885
        CFStreamCreatePairWithSocket(NULL, (CFSocketNativeHandle)socketFD, &readStream, &writeStream);
7886
 
7887
        // The kCFStreamPropertyShouldCloseNativeSocket property should be false by default (for our case).
7888
        // But let's not take any chances.
7889
 
7890
        if (readStream)
7891
                CFReadStreamSetProperty(readStream, kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanFalse);
7892
        if (writeStream)
7893
                CFWriteStreamSetProperty(writeStream, kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanFalse);
7894
 
7895
        if ((readStream == NULL) || (writeStream == NULL))
7896
        {
7897
                LogWarn(@"Unable to create read and write stream...");
7898
 
7899
                if (readStream)
7900
                {
7901
                        CFReadStreamClose(readStream);
7902
                        CFRelease(readStream);
7903
                        readStream = NULL;
7904
                }
7905
                if (writeStream)
7906
                {
7907
                        CFWriteStreamClose(writeStream);
7908
                        CFRelease(writeStream);
7909
                        writeStream = NULL;
7910
                }
7911
 
7912
                return NO;
7913
        }
7914
 
7915
        return YES;
7916
}
7917
 
7918
- (BOOL)registerForStreamCallbacksIncludingReadWrite:(BOOL)includeReadWrite
7919
{
7920
        LogVerbose(@"%@ %@", THIS_METHOD, (includeReadWrite ? @"YES" : @"NO"));
7921
 
7922
        NSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @"Must be dispatched on socketQueue");
7923
        NSAssert((readStream != NULL && writeStream != NULL), @"Read/Write stream is null");
7924
 
7925
        streamContext.version = 0;
7926
        streamContext.info = (__bridge void *)(self);
7927
        streamContext.retain = nil;
7928
        streamContext.release = nil;
7929
        streamContext.copyDescription = nil;
7930
 
7931
        CFOptionFlags readStreamEvents = kCFStreamEventErrorOccurred | kCFStreamEventEndEncountered;
7932
        if (includeReadWrite)
7933
                readStreamEvents |= kCFStreamEventHasBytesAvailable;
7934
 
7935
        if (!CFReadStreamSetClient(readStream, readStreamEvents, &CFReadStreamCallback, &streamContext))
7936
        {
7937
                return NO;
7938
        }
7939
 
7940
        CFOptionFlags writeStreamEvents = kCFStreamEventErrorOccurred | kCFStreamEventEndEncountered;
7941
        if (includeReadWrite)
7942
                writeStreamEvents |= kCFStreamEventCanAcceptBytes;
7943
 
7944
        if (!CFWriteStreamSetClient(writeStream, writeStreamEvents, &CFWriteStreamCallback, &streamContext))
7945
        {
7946
                return NO;
7947
        }
7948
 
7949
        return YES;
7950
}
7951
 
7952
- (BOOL)addStreamsToRunLoop
7953
{
7954
        LogTrace();
7955
 
7956
        NSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @"Must be dispatched on socketQueue");
7957
        NSAssert((readStream != NULL && writeStream != NULL), @"Read/Write stream is null");
7958
 
7959
        if (!(flags & kAddedStreamsToRunLoop))
7960
        {
7961
                LogVerbose(@"Adding streams to runloop...");
7962
 
7963
                [[self class] startCFStreamThreadIfNeeded];
7964
        dispatch_sync(cfstreamThreadSetupQueue, ^{
7965
            [[self class] performSelector:@selector(scheduleCFStreams:)
7966
                                 onThread:cfstreamThread
7967
                               withObject:self
7968
                            waitUntilDone:YES];
7969
        });
7970
                flags |= kAddedStreamsToRunLoop;
7971
        }
7972
 
7973
        return YES;
7974
}
7975
 
7976
- (void)removeStreamsFromRunLoop
7977
{
7978
        LogTrace();
7979
 
7980
        NSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @"Must be dispatched on socketQueue");
7981
        NSAssert((readStream != NULL && writeStream != NULL), @"Read/Write stream is null");
7982
 
7983
        if (flags & kAddedStreamsToRunLoop)
7984
        {
7985
                LogVerbose(@"Removing streams from runloop...");
7986
 
7987
        dispatch_sync(cfstreamThreadSetupQueue, ^{
7988
            [[self class] performSelector:@selector(unscheduleCFStreams:)
7989
                                 onThread:cfstreamThread
7990
                               withObject:self
7991
                            waitUntilDone:YES];
7992
        });
7993
                [[self class] stopCFStreamThreadIfNeeded];
7994
 
7995
                flags &= ~kAddedStreamsToRunLoop;
7996
        }
7997
}
7998
 
7999
- (BOOL)openStreams
8000
{
8001
        LogTrace();
8002
 
8003
        NSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @"Must be dispatched on socketQueue");
8004
        NSAssert((readStream != NULL && writeStream != NULL), @"Read/Write stream is null");
8005
 
8006
        CFStreamStatus readStatus = CFReadStreamGetStatus(readStream);
8007
        CFStreamStatus writeStatus = CFWriteStreamGetStatus(writeStream);
8008
 
8009
        if ((readStatus == kCFStreamStatusNotOpen) || (writeStatus == kCFStreamStatusNotOpen))
8010
        {
8011
                LogVerbose(@"Opening read and write stream...");
8012
 
8013
                BOOL r1 = CFReadStreamOpen(readStream);
8014
                BOOL r2 = CFWriteStreamOpen(writeStream);
8015
 
8016
                if (!r1 || !r2)
8017
                {
8018
                        LogError(@"Error in CFStreamOpen");
8019
                        return NO;
8020
                }
8021
        }
8022
 
8023
        return YES;
8024
}
8025
 
8026
#endif
8027
 
8028
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
8029
#pragma mark Advanced
8030
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
8031
 
8032
/**
8033
 * See header file for big discussion of this method.
8034
**/
8035
- (BOOL)autoDisconnectOnClosedReadStream
8036
{
8037
        // Note: YES means kAllowHalfDuplexConnection is OFF
8038
 
8039
        if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
8040
        {
8041
                return ((config & kAllowHalfDuplexConnection) == 0);
8042
        }
8043
        else
8044
        {
8045
                __block BOOL result;
8046
 
8047
                dispatch_sync(socketQueue, ^{
8048
            result = ((self->config & kAllowHalfDuplexConnection) == 0);
8049
                });
8050
 
8051
                return result;
8052
        }
8053
}
8054
 
8055
/**
8056
 * See header file for big discussion of this method.
8057
**/
8058
- (void)setAutoDisconnectOnClosedReadStream:(BOOL)flag
8059
{
8060
        // Note: YES means kAllowHalfDuplexConnection is OFF
8061
 
8062
        dispatch_block_t block = ^{
8063
 
8064
                if (flag)
8065
            self->config &= ~kAllowHalfDuplexConnection;
8066
                else
8067
            self->config |= kAllowHalfDuplexConnection;
8068
        };
8069
 
8070
        if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
8071
                block();
8072
        else
8073
                dispatch_async(socketQueue, block);
8074
}
8075
 
8076
 
8077
/**
8078
 * See header file for big discussion of this method.
8079
**/
8080
- (void)markSocketQueueTargetQueue:(dispatch_queue_t)socketNewTargetQueue
8081
{
8082
        void *nonNullUnusedPointer = (__bridge void *)self;
8083
        dispatch_queue_set_specific(socketNewTargetQueue, IsOnSocketQueueOrTargetQueueKey, nonNullUnusedPointer, NULL);
8084
}
8085
 
8086
/**
8087
 * See header file for big discussion of this method.
8088
**/
8089
- (void)unmarkSocketQueueTargetQueue:(dispatch_queue_t)socketOldTargetQueue
8090
{
8091
        dispatch_queue_set_specific(socketOldTargetQueue, IsOnSocketQueueOrTargetQueueKey, NULL, NULL);
8092
}
8093
 
8094
/**
8095
 * See header file for big discussion of this method.
8096
**/
8097
- (void)performBlock:(dispatch_block_t)block
8098
{
8099
        if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
8100
                block();
8101
        else
8102
                dispatch_sync(socketQueue, block);
8103
}
8104
 
8105
/**
8106
 * Questions? Have you read the header file?
8107
**/
8108
- (int)socketFD
8109
{
8110
        if (!dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
8111
        {
8112
                LogWarn(@"%@ - Method only available from within the context of a performBlock: invocation", THIS_METHOD);
8113
                return SOCKET_NULL;
8114
        }
8115
 
8116
        if (socket4FD != SOCKET_NULL)
8117
                return socket4FD;
8118
        else
8119
                return socket6FD;
8120
}
8121
 
8122
/**
8123
 * Questions? Have you read the header file?
8124
**/
8125
- (int)socket4FD
8126
{
8127
        if (!dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
8128
        {
8129
                LogWarn(@"%@ - Method only available from within the context of a performBlock: invocation", THIS_METHOD);
8130
                return SOCKET_NULL;
8131
        }
8132
 
8133
        return socket4FD;
8134
}
8135
 
8136
/**
8137
 * Questions? Have you read the header file?
8138
**/
8139
- (int)socket6FD
8140
{
8141
        if (!dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
8142
        {
8143
                LogWarn(@"%@ - Method only available from within the context of a performBlock: invocation", THIS_METHOD);
8144
                return SOCKET_NULL;
8145
        }
8146
 
8147
        return socket6FD;
8148
}
8149
 
8150
#if TARGET_OS_IPHONE
8151
 
8152
/**
8153
 * Questions? Have you read the header file?
8154
**/
8155
- (CFReadStreamRef)readStream
8156
{
8157
        if (!dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
8158
        {
8159
                LogWarn(@"%@ - Method only available from within the context of a performBlock: invocation", THIS_METHOD);
8160
                return NULL;
8161
        }
8162
 
8163
        if (readStream == NULL)
8164
                [self createReadAndWriteStream];
8165
 
8166
        return readStream;
8167
}
8168
 
8169
/**
8170
 * Questions? Have you read the header file?
8171
**/
8172
- (CFWriteStreamRef)writeStream
8173
{
8174
        if (!dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
8175
        {
8176
                LogWarn(@"%@ - Method only available from within the context of a performBlock: invocation", THIS_METHOD);
8177
                return NULL;
8178
        }
8179
 
8180
        if (writeStream == NULL)
8181
                [self createReadAndWriteStream];
8182
 
8183
        return writeStream;
8184
}
8185
 
8186
- (BOOL)enableBackgroundingOnSocketWithCaveat:(BOOL)caveat
8187
{
8188
        if (![self createReadAndWriteStream])
8189
        {
8190
                // Error occurred creating streams (perhaps socket isn't open)
8191
                return NO;
8192
        }
8193
 
8194
        BOOL r1, r2;
8195
 
8196
        LogVerbose(@"Enabling backgrouding on socket");
8197
 
8198
#pragma clang diagnostic push
8199
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
8200
        r1 = CFReadStreamSetProperty(readStream, kCFStreamNetworkServiceType, kCFStreamNetworkServiceTypeVoIP);
8201
        r2 = CFWriteStreamSetProperty(writeStream, kCFStreamNetworkServiceType, kCFStreamNetworkServiceTypeVoIP);
8202
#pragma clang diagnostic pop
8203
 
8204
        if (!r1 || !r2)
8205
        {
8206
                return NO;
8207
        }
8208
 
8209
        if (!caveat)
8210
        {
8211
                if (![self openStreams])
8212
                {
8213
                        return NO;
8214
                }
8215
        }
8216
 
8217
        return YES;
8218
}
8219
 
8220
/**
8221
 * Questions? Have you read the header file?
8222
**/
8223
- (BOOL)enableBackgroundingOnSocket
8224
{
8225
        LogTrace();
8226
 
8227
        if (!dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
8228
        {
8229
                LogWarn(@"%@ - Method only available from within the context of a performBlock: invocation", THIS_METHOD);
8230
                return NO;
8231
        }
8232
 
8233
        return [self enableBackgroundingOnSocketWithCaveat:NO];
8234
}
8235
 
8236
- (BOOL)enableBackgroundingOnSocketWithCaveat // Deprecated in iOS 4.???
8237
{
8238
        // This method was created as a workaround for a bug in iOS.
8239
        // Apple has since fixed this bug.
8240
        // I'm not entirely sure which version of iOS they fixed it in...
8241
 
8242
        LogTrace();
8243
 
8244
        if (!dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
8245
        {
8246
                LogWarn(@"%@ - Method only available from within the context of a performBlock: invocation", THIS_METHOD);
8247
                return NO;
8248
        }
8249
 
8250
        return [self enableBackgroundingOnSocketWithCaveat:YES];
8251
}
8252
 
8253
#endif
8254
 
8255
- (SSLContextRef)sslContext
8256
{
8257
        if (!dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
8258
        {
8259
                LogWarn(@"%@ - Method only available from within the context of a performBlock: invocation", THIS_METHOD);
8260
                return NULL;
8261
        }
8262
 
8263
        return sslContext;
8264
}
8265
 
8266
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
8267
#pragma mark Class Utilities
8268
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
8269
 
8270
+ (NSMutableArray *)lookupHost:(NSString *)host port:(uint16_t)port error:(NSError **)errPtr
8271
{
8272
        LogTrace();
8273
 
8274
        NSMutableArray *addresses = nil;
8275
        NSError *error = nil;
8276
 
8277
        if ([host isEqualToString:@"localhost"] || [host isEqualToString:@"loopback"])
8278
        {
8279
                // Use LOOPBACK address
8280
                struct sockaddr_in nativeAddr4;
8281
                nativeAddr4.sin_len         = sizeof(struct sockaddr_in);
8282
                nativeAddr4.sin_family      = AF_INET;
8283
                nativeAddr4.sin_port        = htons(port);
8284
                nativeAddr4.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
8285
                memset(&(nativeAddr4.sin_zero), 0, sizeof(nativeAddr4.sin_zero));
8286
 
8287
                struct sockaddr_in6 nativeAddr6;
8288
                nativeAddr6.sin6_len        = sizeof(struct sockaddr_in6);
8289
                nativeAddr6.sin6_family     = AF_INET6;
8290
                nativeAddr6.sin6_port       = htons(port);
8291
                nativeAddr6.sin6_flowinfo   = 0;
8292
                nativeAddr6.sin6_addr       = in6addr_loopback;
8293
                nativeAddr6.sin6_scope_id   = 0;
8294
 
8295
                // Wrap the native address structures
8296
 
8297
                NSData *address4 = [NSData dataWithBytes:&nativeAddr4 length:sizeof(nativeAddr4)];
8298
                NSData *address6 = [NSData dataWithBytes:&nativeAddr6 length:sizeof(nativeAddr6)];
8299
 
8300
                addresses = [NSMutableArray arrayWithCapacity:2];
8301
                [addresses addObject:address4];
8302
                [addresses addObject:address6];
8303
        }
8304
        else
8305
        {
8306
                NSString *portStr = [NSString stringWithFormat:@"%hu", port];
8307
 
8308
                struct addrinfo hints, *res, *res0;
8309
 
8310
                memset(&hints, 0, sizeof(hints));
8311
                hints.ai_family   = PF_UNSPEC;
8312
                hints.ai_socktype = SOCK_STREAM;
8313
                hints.ai_protocol = IPPROTO_TCP;
8314
 
8315
                int gai_error = getaddrinfo([host UTF8String], [portStr UTF8String], &hints, &res0);
8316
 
8317
                if (gai_error)
8318
                {
8319
                        error = [self gaiError:gai_error];
8320
                }
8321
                else
8322
                {
8323
                        NSUInteger capacity = 0;
8324
                        for (res = res0; res; res = res->ai_next)
8325
                        {
8326
                                if (res->ai_family == AF_INET || res->ai_family == AF_INET6) {
8327
                                        capacity++;
8328
                                }
8329
                        }
8330
 
8331
                        addresses = [NSMutableArray arrayWithCapacity:capacity];
8332
 
8333
                        for (res = res0; res; res = res->ai_next)
8334
                        {
8335
                                if (res->ai_family == AF_INET)
8336
                                {
8337
                                        // Found IPv4 address.
8338
                                        // Wrap the native address structure, and add to results.
8339
 
8340
                                        NSData *address4 = [NSData dataWithBytes:res->ai_addr length:res->ai_addrlen];
8341
                                        [addresses addObject:address4];
8342
                                }
8343
                                else if (res->ai_family == AF_INET6)
8344
                                {
8345
                                        // Fixes connection issues with IPv6
8346
                                        // https://github.com/robbiehanson/CocoaAsyncSocket/issues/429#issuecomment-222477158
8347
 
8348
                                        // Found IPv6 address.
8349
                                        // Wrap the native address structure, and add to results.
8350
 
8351
                                        struct sockaddr_in6 *sockaddr = (struct sockaddr_in6 *)(void *)res->ai_addr;
8352
                                        in_port_t *portPtr = &sockaddr->sin6_port;
8353
                                        if ((portPtr != NULL) && (*portPtr == 0)) {
8354
                                                *portPtr = htons(port);
8355
                                        }
8356
 
8357
                                        NSData *address6 = [NSData dataWithBytes:res->ai_addr length:res->ai_addrlen];
8358
                                        [addresses addObject:address6];
8359
                                }
8360
                        }
8361
                        freeaddrinfo(res0);
8362
 
8363
                        if ([addresses count] == 0)
8364
                        {
8365
                                error = [self gaiError:EAI_FAIL];
8366
                        }
8367
                }
8368
        }
8369
 
8370
        if (errPtr) *errPtr = error;
8371
        return addresses;
8372
}
8373
 
8374
+ (NSString *)hostFromSockaddr4:(const struct sockaddr_in *)pSockaddr4
8375
{
8376
        char addrBuf[INET_ADDRSTRLEN];
8377
 
8378
        if (inet_ntop(AF_INET, &pSockaddr4->sin_addr, addrBuf, (socklen_t)sizeof(addrBuf)) == NULL)
8379
        {
8380
                addrBuf[0] = '\0';
8381
        }
8382
 
8383
        return [NSString stringWithCString:addrBuf encoding:NSASCIIStringEncoding];
8384
}
8385
 
8386
+ (NSString *)hostFromSockaddr6:(const struct sockaddr_in6 *)pSockaddr6
8387
{
8388
        char addrBuf[INET6_ADDRSTRLEN];
8389
 
8390
        if (inet_ntop(AF_INET6, &pSockaddr6->sin6_addr, addrBuf, (socklen_t)sizeof(addrBuf)) == NULL)
8391
        {
8392
                addrBuf[0] = '\0';
8393
        }
8394
 
8395
        return [NSString stringWithCString:addrBuf encoding:NSASCIIStringEncoding];
8396
}
8397
 
8398
+ (uint16_t)portFromSockaddr4:(const struct sockaddr_in *)pSockaddr4
8399
{
8400
        return ntohs(pSockaddr4->sin_port);
8401
}
8402
 
8403
+ (uint16_t)portFromSockaddr6:(const struct sockaddr_in6 *)pSockaddr6
8404
{
8405
        return ntohs(pSockaddr6->sin6_port);
8406
}
8407
 
8408
+ (NSURL *)urlFromSockaddrUN:(const struct sockaddr_un *)pSockaddr
8409
{
8410
        NSString *path = [NSString stringWithUTF8String:pSockaddr->sun_path];
8411
        return [NSURL fileURLWithPath:path];
8412
}
8413
 
8414
+ (NSString *)hostFromAddress:(NSData *)address
8415
{
8416
        NSString *host;
8417
 
8418
        if ([self getHost:&host port:NULL fromAddress:address])
8419
                return host;
8420
        else
8421
                return nil;
8422
}
8423
 
8424
+ (uint16_t)portFromAddress:(NSData *)address
8425
{
8426
        uint16_t port;
8427
 
8428
        if ([self getHost:NULL port:&port fromAddress:address])
8429
                return port;
8430
        else
8431
                return 0;
8432
}
8433
 
8434
+ (BOOL)isIPv4Address:(NSData *)address
8435
{
8436
        if ([address length] >= sizeof(struct sockaddr))
8437
        {
8438
                const struct sockaddr *sockaddrX = [address bytes];
8439
 
8440
                if (sockaddrX->sa_family == AF_INET) {
8441
                        return YES;
8442
                }
8443
        }
8444
 
8445
        return NO;
8446
}
8447
 
8448
+ (BOOL)isIPv6Address:(NSData *)address
8449
{
8450
        if ([address length] >= sizeof(struct sockaddr))
8451
        {
8452
                const struct sockaddr *sockaddrX = [address bytes];
8453
 
8454
                if (sockaddrX->sa_family == AF_INET6) {
8455
                        return YES;
8456
                }
8457
        }
8458
 
8459
        return NO;
8460
}
8461
 
8462
+ (BOOL)getHost:(NSString **)hostPtr port:(uint16_t *)portPtr fromAddress:(NSData *)address
8463
{
8464
        return [self getHost:hostPtr port:portPtr family:NULL fromAddress:address];
8465
}
8466
 
8467
+ (BOOL)getHost:(NSString **)hostPtr port:(uint16_t *)portPtr family:(sa_family_t *)afPtr fromAddress:(NSData *)address
8468
{
8469
        if ([address length] >= sizeof(struct sockaddr))
8470
        {
8471
                const struct sockaddr *sockaddrX = [address bytes];
8472
 
8473
                if (sockaddrX->sa_family == AF_INET)
8474
                {
8475
                        if ([address length] >= sizeof(struct sockaddr_in))
8476
                        {
8477
                                struct sockaddr_in sockaddr4;
8478
                                memcpy(&sockaddr4, sockaddrX, sizeof(sockaddr4));
8479
 
8480
                                if (hostPtr) *hostPtr = [self hostFromSockaddr4:&sockaddr4];
8481
                                if (portPtr) *portPtr = [self portFromSockaddr4:&sockaddr4];
8482
                                if (afPtr)   *afPtr   = AF_INET;
8483
 
8484
                                return YES;
8485
                        }
8486
                }
8487
                else if (sockaddrX->sa_family == AF_INET6)
8488
                {
8489
                        if ([address length] >= sizeof(struct sockaddr_in6))
8490
                        {
8491
                                struct sockaddr_in6 sockaddr6;
8492
                                memcpy(&sockaddr6, sockaddrX, sizeof(sockaddr6));
8493
 
8494
                                if (hostPtr) *hostPtr = [self hostFromSockaddr6:&sockaddr6];
8495
                                if (portPtr) *portPtr = [self portFromSockaddr6:&sockaddr6];
8496
                                if (afPtr)   *afPtr   = AF_INET6;
8497
 
8498
                                return YES;
8499
                        }
8500
                }
8501
        }
8502
 
8503
        return NO;
8504
}
8505
 
8506
+ (NSData *)CRLFData
8507
{
8508
        return [NSData dataWithBytes:"\x0D\x0A" length:2];
8509
}
8510
 
8511
+ (NSData *)CRData
8512
{
8513
        return [NSData dataWithBytes:"\x0D" length:1];
8514
}
8515
 
8516
+ (NSData *)LFData
8517
{
8518
        return [NSData dataWithBytes:"\x0A" length:1];
8519
}
8520
 
8521
+ (NSData *)ZeroData
8522
{
8523
        return [NSData dataWithBytes:"" length:1];
8524
}
8525
 
8526
@end