Skip to content
Browse files

Merging latest changes from CocoaAsyncSocket project

  • Loading branch information...
1 parent a39bc1a commit 4972df648568a68242de78806bfb8e2c7c6efc2c @robbiehanson committed
Showing with 548 additions and 242 deletions.
  1. +18 −4 Vendor/CocoaAsyncSocket/GCDAsyncSocket.h
  2. +530 −238 Vendor/CocoaAsyncSocket/GCDAsyncSocket.m
View
22 Vendor/CocoaAsyncSocket/GCDAsyncSocket.h
@@ -3,9 +3,9 @@
//
// This class is in the public domain.
// Originally created by Robbie Hanson in Q3 2010.
-// Updated and maintained by Deusty LLC and the Mac development community.
+// Updated and maintained by Deusty LLC and the Apple development community.
//
-// http://code.google.com/p/cocoaasyncsocket/
+// https://github.com/robbiehanson/CocoaAsyncSocket
//
#import <Foundation/Foundation.h>
@@ -15,6 +15,7 @@
@class GCDAsyncReadPacket;
@class GCDAsyncWritePacket;
+@class GCDAsyncSocketPreBuffer;
#if TARGET_OS_IPHONE
@@ -128,7 +129,7 @@ typedef enum GCDAsyncSocketError GCDAsyncSocketError;
unsigned long socketFDBytesAvailable;
- NSMutableData *partialReadBuffer;
+ GCDAsyncSocketPreBuffer *preBuffer;
#if TARGET_OS_IPHONE
CFStreamClientContext streamContext;
@@ -137,8 +138,9 @@ typedef enum GCDAsyncSocketError GCDAsyncSocketError;
#endif
#if SECURE_TRANSPORT_MAYBE_AVAILABLE
SSLContextRef sslContext;
- NSMutableData *sslReadBuffer;
+ GCDAsyncSocketPreBuffer *sslPreBuffer;
size_t sslWriteCachedLength;
+ OSStatus sslErrCode;
#endif
id userData;
@@ -702,6 +704,12 @@ typedef enum GCDAsyncSocketError GCDAsyncSocketError;
maxLength:(NSUInteger)length
tag:(long)tag;
+/**
+ * Returns progress of the current read, from 0.0 to 1.0, or NaN if no current read (use isnan() to check).
+ * The parameters "tag", "done" and "total" will be filled in if they aren't NULL.
+**/
+- (float)progressOfReadReturningTag:(long *)tagPtr bytesDone:(NSUInteger *)donePtr total:(NSUInteger *)totalPtr;
+
#pragma mark Writing
/**
@@ -723,6 +731,12 @@ typedef enum GCDAsyncSocketError GCDAsyncSocketError;
**/
- (void)writeData:(NSData *)data withTimeout:(NSTimeInterval)timeout tag:(long)tag;
+/**
+ * Returns progress of the current write, from 0.0 to 1.0, or NaN if no current write (use isnan() to check).
+ * The parameters "tag", "done" and "total" will be filled in if they aren't NULL.
+**/
+- (float)progressOfWriteReturningTag:(long *)tagPtr bytesDone:(NSUInteger *)donePtr total:(NSUInteger *)totalPtr;
+
#pragma mark Security
/**
View
768 Vendor/CocoaAsyncSocket/GCDAsyncSocket.m
@@ -3,13 +3,40 @@
//
// This class is in the public domain.
// Originally created by Robbie Hanson in Q4 2010.
-// Updated and maintained by Deusty LLC and the Mac development community.
+// Updated and maintained by Deusty LLC and the Apple development community.
//
-// http://code.google.com/p/cocoaasyncsocket/
+// https://github.com/robbiehanson/CocoaAsyncSocket
//
#if ! __has_feature(objc_arc)
#warning This file must be compiled with ARC. Use -fobjc-arc flag (or convert project to ARC).
+// For more information see: https://github.com/robbiehanson/CocoaAsyncSocket/wiki/ARC
+#endif
+
+/**
+ * Does ARC support support GCD objects?
+ * It does if the minimum deployment target is iOS 6+ or Mac OS X 8+
+**/
+#if TARGET_OS_IPHONE
+
+ // Compiling for iOS
+
+ #if __IPHONE_OS_VERSION_MIN_REQUIRED >= 60000 // iOS 6.0 or later
+ #define NEEDS_DISPATCH_RETAIN_RELEASE 0
+ #else // iOS 5.X or earlier
+ #define NEEDS_DISPATCH_RETAIN_RELEASE 1
+ #endif
+
+#else
+
+ // Compiling for Mac OS X
+
+ #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1080 // Mac OS X 10.8 or later
+ #define NEEDS_DISPATCH_RETAIN_RELEASE 0
+ #else
+ #define NEEDS_DISPATCH_RETAIN_RELEASE 1 // Mac OS X 10.7 or earlier
+ #endif
+
#endif
#import "GCDAsyncSocket.h"
@@ -263,6 +290,158 @@ + (uint16_t)portFromSockaddr6:(const struct sockaddr_in6 *)pSockaddr6;
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
+ * A PreBuffer is used when there is more data available on the socket
+ * than is being requested by current read request.
+ * In this case we slurp up all data from the socket (to minimize sys calls),
+ * and store additional yet unread data in a "prebuffer".
+ *
+ * The prebuffer is entirely drained before we read from the socket again.
+ * In other words, a large chunk of data is written is written to the prebuffer.
+ * The prebuffer is then drained via a series of one or more reads (for subsequent read request(s)).
+ *
+ * A ring buffer was once used for this purpose.
+ * But a ring buffer takes up twice as much memory as needed (double the size for mirroring).
+ * In fact, it generally takes up more than twice the needed size as everything has to be rounded up to vm_page_size.
+ * And since the prebuffer is always completely drained after being written to, a full ring buffer isn't needed.
+ *
+ * The current design is very simple and straight-forward, while also keeping memory requirements lower.
+**/
+
+@interface GCDAsyncSocketPreBuffer : NSObject
+{
+ uint8_t *preBuffer;
+ size_t preBufferSize;
+
+ uint8_t *readPointer;
+ uint8_t *writePointer;
+}
+
+- (id)initWithCapacity:(size_t)numBytes;
+
+- (void)ensureCapacityForWrite:(size_t)numBytes;
+
+- (size_t)availableBytes;
+- (uint8_t *)readBuffer;
+
+- (void)getReadBuffer:(uint8_t **)bufferPtr availableBytes:(size_t *)availableBytesPtr;
+
+- (size_t)availableSpace;
+- (uint8_t *)writeBuffer;
+
+- (void)getWriteBuffer:(uint8_t **)bufferPtr availableSpace:(size_t *)availableSpacePtr;
+
+- (void)didRead:(size_t)bytesRead;
+- (void)didWrite:(size_t)bytesWritten;
+
+- (void)reset;
+
+@end
+
+@implementation GCDAsyncSocketPreBuffer
+
+- (id)initWithCapacity:(size_t)numBytes
+{
+ if ((self = [super init]))
+ {
+ preBufferSize = numBytes;
+ preBuffer = malloc(preBufferSize);
+
+ readPointer = preBuffer;
+ writePointer = preBuffer;
+ }
+ return self;
+}
+
+- (void)dealloc
+{
+ if (preBuffer)
+ free(preBuffer);
+}
+
+- (void)ensureCapacityForWrite:(size_t)numBytes
+{
+ size_t availableSpace = preBufferSize - (writePointer - readPointer);
+
+ if (numBytes > availableSpace)
+ {
+ size_t additionalBytes = numBytes - availableSpace;
+
+ size_t newPreBufferSize = preBufferSize + additionalBytes;
+ uint8_t *newPreBuffer = realloc(preBuffer, newPreBufferSize);
+
+ size_t readPointerOffset = readPointer - preBuffer;
+ size_t writePointerOffset = writePointer - preBuffer;
+
+ preBuffer = newPreBuffer;
+ preBufferSize = newPreBufferSize;
+
+ readPointer = preBuffer + readPointerOffset;
+ writePointer = preBuffer + writePointerOffset;
+ }
+}
+
+- (size_t)availableBytes
+{
+ return writePointer - readPointer;
+}
+
+- (uint8_t *)readBuffer
+{
+ return readPointer;
+}
+
+- (void)getReadBuffer:(uint8_t **)bufferPtr availableBytes:(size_t *)availableBytesPtr
+{
+ if (bufferPtr) *bufferPtr = readPointer;
+ if (availableBytesPtr) *availableBytesPtr = writePointer - readPointer;
+}
+
+- (void)didRead:(size_t)bytesRead
+{
+ readPointer += bytesRead;
+
+ if (readPointer == writePointer)
+ {
+ // The prebuffer has been drained. Reset pointers.
+ readPointer = preBuffer;
+ writePointer = preBuffer;
+ }
+}
+
+- (size_t)availableSpace
+{
+ return preBufferSize - (writePointer - readPointer);
+}
+
+- (uint8_t *)writeBuffer
+{
+ return writePointer;
+}
+
+- (void)getWriteBuffer:(uint8_t **)bufferPtr availableSpace:(size_t *)availableSpacePtr
+{
+ if (bufferPtr) *bufferPtr = writePointer;
+ if (availableSpacePtr) *availableSpacePtr = preBufferSize - (writePointer - readPointer);
+}
+
+- (void)didWrite:(size_t)bytesWritten
+{
+ writePointer += bytesWritten;
+}
+
+- (void)reset
+{
+ readPointer = preBuffer;
+ writePointer = preBuffer;
+}
+
+@end
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+#pragma mark -
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+/**
* The GCDAsyncReadPacket encompasses the instructions for any given read.
* The content of a read packet allows the code to determine if we're:
* - reading to a certain length
@@ -297,7 +476,7 @@ - (NSUInteger)optimalReadLengthWithDefault:(NSUInteger)defaultValue shouldPreBuf
- (NSUInteger)readLengthForNonTermWithHint:(NSUInteger)bytesAvailable;
- (NSUInteger)readLengthForTermWithHint:(NSUInteger)bytesAvailable shouldPreBuffer:(BOOL *)shouldPreBufferPtr;
-- (NSUInteger)readLengthForTermWithPreBuffer:(NSData *)preBuffer found:(BOOL *)foundPtr;
+- (NSUInteger)readLengthForTermWithPreBuffer:(GCDAsyncSocketPreBuffer *)preBuffer found:(BOOL *)foundPtr;
- (NSInteger)searchForTermAfterPreBuffering:(ssize_t)numBytes;
@@ -561,13 +740,13 @@ - (NSUInteger)readLengthForTermWithHint:(NSUInteger)bytesAvailable shouldPreBuff
*
* It is assumed the terminator has not already been read.
**/
-- (NSUInteger)readLengthForTermWithPreBuffer:(NSData *)preBuffer found:(BOOL *)foundPtr
+- (NSUInteger)readLengthForTermWithPreBuffer:(GCDAsyncSocketPreBuffer *)preBuffer found:(BOOL *)foundPtr
{
NSAssert(term != nil, @"This method does not apply to non-term reads");
- NSAssert([preBuffer length] > 0, @"Invoked with empty pre buffer!");
+ NSAssert([preBuffer availableBytes] > 0, @"Invoked with empty pre buffer!");
// We know that the terminator, as a whole, doesn't exist in our own buffer.
- // But it is possible that a portion of it exists in our buffer.
+ // But it is possible that a _portion_ of it exists in our buffer.
// So we're going to look for the terminator starting with a portion of our own buffer.
//
// Example:
@@ -604,7 +783,7 @@ - (NSUInteger)readLengthForTermWithPreBuffer:(NSData *)preBuffer found:(BOOL *)f
BOOL found = NO;
NSUInteger termLength = [term length];
- NSUInteger preBufferLength = [preBuffer length];
+ NSUInteger preBufferLength = [preBuffer availableBytes];
if ((bytesDone + preBufferLength) < termLength)
{
@@ -629,11 +808,11 @@ - (NSUInteger)readLengthForTermWithPreBuffer:(NSData *)preBuffer found:(BOOL *)f
uint8_t *buf = (uint8_t *)[buffer mutableBytes] + startOffset + bytesDone - bufLen;
NSUInteger preLen = termLength - bufLen;
- const uint8_t *pre = [preBuffer bytes];
+ const uint8_t *pre = [preBuffer readBuffer];
NSUInteger loopCount = bufLen + maxPreBufferLength - termLength + 1; // Plus one. See example above.
- NSUInteger result = preBufferLength;
+ NSUInteger result = maxPreBufferLength;
NSUInteger i;
for (i = 0; i < loopCount; i++)
@@ -662,7 +841,7 @@ - (NSUInteger)readLengthForTermWithPreBuffer:(NSData *)preBuffer found:(BOOL *)f
if (memcmp(pre, termBuf, termLength) == 0)
{
- NSUInteger preOffset = pre - (const uint8_t *)[preBuffer bytes]; // pointer arithmetic
+ NSUInteger preOffset = pre - [preBuffer readBuffer]; // pointer arithmetic
result = preOffset + termLength;
found = YES;
@@ -819,12 +998,11 @@ - (id)initWithDelegate:(id)aDelegate delegateQueue:(dispatch_queue_t)dq socketQu
if((self = [super init]))
{
delegate = aDelegate;
+ delegateQueue = dq;
- if (dq)
- {
- dispatch_retain(dq);
- delegateQueue = dq;
- }
+ #if NEEDS_DISPATCH_RETAIN_RELEASE
+ if (dq) dispatch_retain(dq);
+ #endif
socket4FD = SOCKET_NULL;
socket6FD = SOCKET_NULL;
@@ -839,8 +1017,10 @@ - (id)initWithDelegate:(id)aDelegate delegateQueue:(dispatch_queue_t)dq socketQu
NSAssert(sq != dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),
@"The given socketQueue parameter must not be a concurrent queue.");
- dispatch_retain(sq);
socketQueue = sq;
+ #if NEEDS_DISPATCH_RETAIN_RELEASE
+ dispatch_retain(sq);
+ #endif
}
else
{
@@ -853,7 +1033,7 @@ - (id)initWithDelegate:(id)aDelegate delegateQueue:(dispatch_queue_t)dq socketQu
writeQueue = [[NSMutableArray alloc] initWithCapacity:5];
currentWrite = nil;
- partialReadBuffer = [[NSMutableData alloc] init];
+ preBuffer = [[GCDAsyncSocketPreBuffer alloc] initWithCapacity:(1024 * 4)];
}
return self;
}
@@ -874,12 +1054,15 @@ - (void)dealloc
}
delegate = nil;
- if (delegateQueue)
- dispatch_release(delegateQueue);
+
+ #if NEEDS_DISPATCH_RETAIN_RELEASE
+ if (delegateQueue) dispatch_release(delegateQueue);
+ #endif
delegateQueue = NULL;
- if (socketQueue)
- dispatch_release(socketQueue);
+ #if NEEDS_DISPATCH_RETAIN_RELEASE
+ if (socketQueue) dispatch_release(socketQueue);
+ #endif
socketQueue = NULL;
LogInfo(@"%@ - %@ (finish)", THIS_METHOD, self);
@@ -956,11 +1139,10 @@ - (void)setDelegateQueue:(dispatch_queue_t)newDelegateQueue synchronously:(BOOL)
{
dispatch_block_t block = ^{
- if (delegateQueue)
- dispatch_release(delegateQueue);
-
- if (newDelegateQueue)
- dispatch_retain(newDelegateQueue);
+ #if NEEDS_DISPATCH_RETAIN_RELEASE
+ if (delegateQueue) dispatch_release(delegateQueue);
+ if (newDelegateQueue) dispatch_retain(newDelegateQueue);
+ #endif
delegateQueue = newDelegateQueue;
};
@@ -1014,11 +1196,10 @@ - (void)setDelegate:(id)newDelegate delegateQueue:(dispatch_queue_t)newDelegateQ
delegate = newDelegate;
- if (delegateQueue)
- dispatch_release(delegateQueue);
-
- if (newDelegateQueue)
- dispatch_retain(newDelegateQueue);
+ #if NEEDS_DISPATCH_RETAIN_RELEASE
+ if (delegateQueue) dispatch_release(delegateQueue);
+ if (newDelegateQueue) dispatch_retain(newDelegateQueue);
+ #endif
delegateQueue = newDelegateQueue;
};
@@ -1273,6 +1454,7 @@ - (BOOL)acceptOnInterface:(NSString *)inInterface port:(uint16_t)port error:(NSE
NSString *reason = @"Error enabling non-blocking IO on socket (fcntl)";
err = [self errnoErrorWithReason:reason];
+ LogVerbose(@"close(socketFD)");
close(socketFD);
return SOCKET_NULL;
}
@@ -1284,6 +1466,7 @@ - (BOOL)acceptOnInterface:(NSString *)inInterface port:(uint16_t)port error:(NSE
NSString *reason = @"Error enabling address reuse (setsockopt)";
err = [self errnoErrorWithReason:reason];
+ LogVerbose(@"close(socketFD)");
close(socketFD);
return SOCKET_NULL;
}
@@ -1296,6 +1479,7 @@ - (BOOL)acceptOnInterface:(NSString *)inInterface port:(uint16_t)port error:(NSE
NSString *reason = @"Error in bind() function";
err = [self errnoErrorWithReason:reason];
+ LogVerbose(@"close(socketFD)");
close(socketFD);
return SOCKET_NULL;
}
@@ -1308,6 +1492,7 @@ - (BOOL)acceptOnInterface:(NSString *)inInterface port:(uint16_t)port error:(NSE
NSString *reason = @"Error in listen() function";
err = [self errnoErrorWithReason:reason];
+ LogVerbose(@"close(socketFD)");
close(socketFD);
return SOCKET_NULL;
}
@@ -1424,6 +1609,7 @@ - (BOOL)acceptOnInterface:(NSString *)inInterface port:(uint16_t)port error:(NSE
{
if (socket4FD != SOCKET_NULL)
{
+ LogVerbose(@"close(socket4FD)");
close(socket4FD);
}
@@ -1454,8 +1640,10 @@ - (BOOL)acceptOnInterface:(NSString *)inInterface port:(uint16_t)port error:(NSE
dispatch_source_set_cancel_handler(accept4Source, ^{
+ #if NEEDS_DISPATCH_RETAIN_RELEASE
LogVerbose(@"dispatch_release(accept4Source)");
dispatch_release(acceptSource);
+ #endif
LogVerbose(@"close(socket4FD)");
close(socketFD);
@@ -1486,8 +1674,10 @@ - (BOOL)acceptOnInterface:(NSString *)inInterface port:(uint16_t)port error:(NSE
dispatch_source_set_cancel_handler(accept6Source, ^{
+ #if NEEDS_DISPATCH_RETAIN_RELEASE
LogVerbose(@"dispatch_release(accept6Source)");
dispatch_release(acceptSource);
+ #endif
LogVerbose(@"close(socket6FD)");
close(socketFD);
@@ -1621,8 +1811,9 @@ - (BOOL)doAccept:(int)parentSocketFD
}
// Release the socket queue returned from the delegate (it was retained by acceptedSocket)
- if (childSocketQueue)
- dispatch_release(childSocketQueue);
+ #if NEEDS_DISPATCH_RETAIN_RELEASE
+ if (childSocketQueue) dispatch_release(childSocketQueue);
+ #endif
// The accepted socket should have been retained by the delegate.
// Otherwise it gets properly released when exiting the block.
@@ -2182,6 +2373,11 @@ - (BOOL)connectWithAddress4:(NSData *)address4 address6:(NSData *)address6 error
}
}
+ // Prevent SIGPIPE signals
+
+ int nosigpipe = 1;
+ setsockopt(socketFD, SOL_SOCKET, SO_NOSIGPIPE, &nosigpipe, sizeof(nosigpipe));
+
// Start the connection process in a background queue
int aConnectIndex = connectIndex;
@@ -2330,11 +2526,6 @@ - (void)didConnect:(int)aConnectIndex
return;
}
- // Prevent SIGPIPE signals
-
- int nosigpipe = 1;
- setsockopt(socketFD, SOL_SOCKET, SO_NOSIGPIPE, &nosigpipe, sizeof(nosigpipe));
-
// Setup our read/write sources
[self setupReadAndWriteSourcesForNewlyConnectedSocket:socketFD];
@@ -2361,7 +2552,6 @@ - (void)didNotConnect:(int)aConnectIndex error:(NSError *)error
return;
}
- [self endConnectTimeout];
[self closeWithError:error];
}
@@ -2376,11 +2566,13 @@ - (void)startConnectTimeout:(NSTimeInterval)timeout
[self doConnectTimeout];
}});
+ #if NEEDS_DISPATCH_RETAIN_RELEASE
dispatch_source_t theConnectTimer = connectTimer;
dispatch_source_set_cancel_handler(connectTimer, ^{
LogVerbose(@"dispatch_release(connectTimer)");
dispatch_release(theConnectTimer);
});
+ #endif
dispatch_time_t tt = dispatch_time(DISPATCH_TIME_NOW, (timeout * NSEC_PER_SEC));
dispatch_source_set_timer(connectTimer, tt, DISPATCH_TIME_FOREVER, 0);
@@ -2444,7 +2636,7 @@ - (void)closeWithError:(NSError *)error
[readQueue removeAllObjects];
[writeQueue removeAllObjects];
- [partialReadBuffer setLength:0];
+ [preBuffer reset];
#if TARGET_OS_IPHONE
{
@@ -2471,7 +2663,9 @@ - (void)closeWithError:(NSError *)error
#endif
#if SECURE_TRANSPORT_MAYBE_AVAILABLE
{
- [sslReadBuffer setLength:0];
+ [sslPreBuffer reset];
+ sslErrCode = noErr;
+
if (sslContext)
{
// Getting a linker error here about the SSLx() functions?
@@ -2494,62 +2688,72 @@ - (void)closeWithError:(NSError *)error
// So we have to unpause the source if needed.
// This allows the cancel handler to be run, which in turn releases the source and closes the socket.
- if (accept4Source)
+ if (!accept4Source && !accept6Source && !readSource && !writeSource)
{
- LogVerbose(@"dispatch_source_cancel(accept4Source)");
- dispatch_source_cancel(accept4Source);
-
- // We never suspend accept4Source
-
- accept4Source = NULL;
- }
-
- if (accept6Source)
- {
- LogVerbose(@"dispatch_source_cancel(accept6Source)");
- dispatch_source_cancel(accept6Source);
-
- // We never suspend accept6Source
-
- accept6Source = NULL;
- }
- if (!readSource && !writeSource) {
LogVerbose(@"manually closing close");
- if (socket4FD) {
+ if (socket4FD != SOCKET_NULL)
+ {
+ LogVerbose(@"close(socket4FD)");
close(socket4FD);
+ socket4FD = SOCKET_NULL;
}
- if (socket6FD) {
+ if (socket6FD != SOCKET_NULL)
+ {
+ LogVerbose(@"close(socket6FD)");
close(socket6FD);
+ socket6FD = SOCKET_NULL;
}
}
-
- if (readSource)
+ else
{
- LogVerbose(@"dispatch_source_cancel(readSource)");
- dispatch_source_cancel(readSource);
-
- [self resumeReadSource];
+ if (accept4Source)
+ {
+ LogVerbose(@"dispatch_source_cancel(accept4Source)");
+ dispatch_source_cancel(accept4Source);
+
+ // We never suspend accept4Source
+
+ accept4Source = NULL;
+ }
- readSource = NULL;
- }
+ if (accept6Source)
+ {
+ LogVerbose(@"dispatch_source_cancel(accept6Source)");
+ dispatch_source_cancel(accept6Source);
+
+ // We never suspend accept6Source
+
+ accept6Source = NULL;
+ }
- if (writeSource)
- {
- LogVerbose(@"dispatch_source_cancel(writeSource)");
- dispatch_source_cancel(writeSource);
+ if (readSource)
+ {
+ LogVerbose(@"dispatch_source_cancel(readSource)");
+ dispatch_source_cancel(readSource);
+
+ [self resumeReadSource];
+
+ readSource = NULL;
+ }
- [self resumeWriteSource];
+ if (writeSource)
+ {
+ LogVerbose(@"dispatch_source_cancel(writeSource)");
+ dispatch_source_cancel(writeSource);
+
+ [self resumeWriteSource];
+
+ writeSource = NULL;
+ }
- writeSource = NULL;
+ // The sockets will be closed by the cancel handlers of the corresponding source
+
+ socket4FD = SOCKET_NULL;
+ socket6FD = SOCKET_NULL;
}
- // The sockets will be closed by the cancel handlers of the corresponding source
-
- socket4FD = SOCKET_NULL;
- socket6FD = SOCKET_NULL;
-
// If the client has passed the connect/accept method, then the connection has at least begun.
// Notify delegate that it is now ending.
BOOL shouldCallDelegate = (flags & kSocketStarted);
@@ -3428,15 +3632,19 @@ - (void)setupReadAndWriteSourcesForNewlyConnectedSocket:(int)socketFD
__block int socketFDRefCount = 2;
+ #if NEEDS_DISPATCH_RETAIN_RELEASE
dispatch_source_t theReadSource = readSource;
dispatch_source_t theWriteSource = writeSource;
+ #endif
dispatch_source_set_cancel_handler(readSource, ^{
LogVerbose(@"readCancelBlock");
+ #if NEEDS_DISPATCH_RETAIN_RELEASE
LogVerbose(@"dispatch_release(readSource)");
dispatch_release(theReadSource);
+ #endif
if (--socketFDRefCount == 0)
{
@@ -3449,8 +3657,10 @@ - (void)setupReadAndWriteSourcesForNewlyConnectedSocket:(int)socketFD
LogVerbose(@"writeCancelBlock");
+ #if NEEDS_DISPATCH_RETAIN_RELEASE
LogVerbose(@"dispatch_release(writeSource)");
dispatch_release(theWriteSource);
+ #endif
if (--socketFDRefCount == 0)
{
@@ -3702,6 +3912,50 @@ - (void)readDataToData:(NSData *)data
// as the queue might get released without the block completing.
}
+- (float)progressOfReadReturningTag:(long *)tagPtr bytesDone:(NSUInteger *)donePtr total:(NSUInteger *)totalPtr
+{
+ __block float result = 0.0F;
+
+ dispatch_block_t block = ^{
+
+ if (!currentRead || ![currentRead isKindOfClass:[GCDAsyncReadPacket class]])
+ {
+ // We're not reading anything right now.
+
+ if (tagPtr != NULL) *tagPtr = 0;
+ if (donePtr != NULL) *donePtr = 0;
+ if (totalPtr != NULL) *totalPtr = 0;
+
+ result = NAN;
+ }
+ else
+ {
+ // It's only possible to know the progress of our read if we're reading to a certain length.
+ // If we're reading to data, we of course have no idea when the data will arrive.
+ // If we're reading to timeout, then we have no idea when the next chunk of data will arrive.
+
+ NSUInteger done = currentRead->bytesDone;
+ NSUInteger total = currentRead->readLength;
+
+ if (tagPtr != NULL) *tagPtr = currentRead->tag;
+ if (donePtr != NULL) *donePtr = done;
+ if (totalPtr != NULL) *totalPtr = total;
+
+ if (total > 0)
+ result = (float)done / (float)total;
+ else
+ result = 1.0F;
+ }
+ };
+
+ if (dispatch_get_current_queue() == socketQueue)
+ block();
+ else
+ dispatch_sync(socketQueue, block);
+
+ return result;
+}
+
/**
* This method starts a new read, if needed.
*
@@ -3776,7 +4030,7 @@ - (void)maybeDequeueRead
//
// Be sure callbacks are enabled so we're notified about a disconnection.
- if ([partialReadBuffer length] == 0)
+ if ([preBuffer availableBytes] == 0)
{
if ([self usingCFStreamForTLS]) {
// Callbacks never disabled
@@ -3795,10 +4049,10 @@ - (void)flushSSLBuffers
NSAssert((flags & kSocketSecure), @"Cannot flush ssl buffers on non-secure socket");
- if ([partialReadBuffer length] > 0)
+ if ([preBuffer availableBytes] > 0)
{
- // Only flush the ssl buffers if the partialReadBuffer is empty.
- // This is to avoid growing the partialReadBuffer inifinitely large.
+ // Only flush the ssl buffers if the prebuffer is empty.
+ // This is to avoid growing the prebuffer inifinitely large.
return;
}
@@ -3809,25 +4063,20 @@ - (void)flushSSLBuffers
{
if ((flags & kSecureSocketHasBytesAvailable) && CFReadStreamHasBytesAvailable(readStream))
{
- LogVerbose(@"%@ - Flushing ssl buffers into partialReadBuffer...", THIS_METHOD);
+ LogVerbose(@"%@ - Flushing ssl buffers into prebuffer...", THIS_METHOD);
- CFIndex defaultBytesToRead = (1024 * 16);
+ CFIndex defaultBytesToRead = (1024 * 4);
- NSUInteger partialReadBufferOffset = [partialReadBuffer length];
- [partialReadBuffer increaseLengthBy:defaultBytesToRead];
+ [preBuffer ensureCapacityForWrite:defaultBytesToRead];
- uint8_t *buffer = [partialReadBuffer mutableBytes] + partialReadBufferOffset;
+ uint8_t *buffer = [preBuffer writeBuffer];
CFIndex result = CFReadStreamRead(readStream, buffer, defaultBytesToRead);
LogVerbose(@"%@ - CFReadStreamRead(): result = %i", THIS_METHOD, (int)result);
- if (result <= 0)
- {
- [partialReadBuffer setLength:partialReadBufferOffset];
- }
- else
+ if (result > 0)
{
- [partialReadBuffer setLength:(partialReadBufferOffset + result)];
+ [preBuffer didWrite:result];
}
flags &= ~kSecureSocketHasBytesAvailable;
@@ -3845,15 +4094,15 @@ - (void)flushSSLBuffers
// Figure out if there is any data available to be read
//
- // socketFDBytesAvailable <- Number of encrypted bytes we haven't read from the bsd socket
- // [sslReadBuffer length] <- Number of encrypted bytes we've buffered from bsd socket
- // sslInternalBufSize <- Number of decrypted bytes SecureTransport has buffered
+ // socketFDBytesAvailable <- Number of encrypted bytes we haven't read from the bsd socket
+ // [sslPreBuffer availableBytes] <- Number of encrypted bytes we've buffered from bsd socket
+ // sslInternalBufSize <- Number of decrypted bytes SecureTransport has buffered
//
// We call the variable "estimated" because we don't know how many decrypted bytes we'll get
- // from the encrypted bytes in the sslReadBuffer.
+ // from the encrypted bytes in the sslPreBuffer.
// However, we do know this is an upper bound on the estimation.
- estimatedBytesAvailable = socketFDBytesAvailable + [sslReadBuffer length];
+ estimatedBytesAvailable = socketFDBytesAvailable + [sslPreBuffer availableBytes];
size_t sslInternalBufSize = 0;
SSLGetBufferedReadSize(sslContext, &sslInternalBufSize);
@@ -3865,28 +4114,31 @@ - (void)flushSSLBuffers
if (estimatedBytesAvailable > 0)
{
- LogVerbose(@"%@ - Flushing ssl buffers into partialReadBuffer...", THIS_METHOD);
+ LogVerbose(@"%@ - Flushing ssl buffers into prebuffer...", THIS_METHOD);
BOOL done = NO;
do
{
LogVerbose(@"%@ - estimatedBytesAvailable = %lu", THIS_METHOD, (unsigned long)estimatedBytesAvailable);
- // Make room in the partialReadBuffer
+ // Make sure there's enough room in the prebuffer
- NSUInteger partialReadBufferOffset = [partialReadBuffer length];
- [partialReadBuffer increaseLengthBy:estimatedBytesAvailable];
+ [preBuffer ensureCapacityForWrite:estimatedBytesAvailable];
- uint8_t *buffer = (uint8_t *)[partialReadBuffer mutableBytes] + partialReadBufferOffset;
- size_t bytesRead = 0;
+ // Read data into prebuffer
- // Read data into partialReadBuffer
+ uint8_t *buffer = [preBuffer writeBuffer];
+ size_t bytesRead = 0;
OSStatus result = SSLRead(sslContext, buffer, (size_t)estimatedBytesAvailable, &bytesRead);
LogVerbose(@"%@ - read from secure socket = %u", THIS_METHOD, (unsigned)bytesRead);
- [partialReadBuffer setLength:(partialReadBufferOffset + bytesRead)];
- LogVerbose(@"%@ - partialReadBuffer.length = %lu", THIS_METHOD, (unsigned long)[partialReadBuffer length]);
+ if (bytesRead > 0)
+ {
+ [preBuffer didWrite:bytesRead];
+ }
+
+ LogVerbose(@"%@ - prebuffer.length = %zu", THIS_METHOD, [preBuffer availableBytes]);
if (result != noErr)
{
@@ -3993,9 +4245,9 @@ - (void)doReadData
// This has to do with the encypted packets that are coming across the TCP stream.
// But it's non-optimal to do a bunch of small reads from the BSD socket.
// So our SSLReadFunction reads all available data from the socket (optimizing the sys call)
- // and may store excess in the sslReadBuffer.
+ // and may store excess in the sslPreBuffer.
- estimatedBytesAvailable += [sslReadBuffer length];
+ estimatedBytesAvailable += [sslPreBuffer availableBytes];
// The second buffer is within SecureTransport.
// As mentioned earlier, there are encrypted packets coming across the TCP stream.
@@ -4020,7 +4272,7 @@ - (void)doReadData
#endif
}
- if ((hasBytesAvailable == NO) && ([partialReadBuffer length] == 0))
+ if ((hasBytesAvailable == NO) && ([preBuffer availableBytes] == 0))
{
LogVerbose(@"No data available to read...");
@@ -4081,9 +4333,7 @@ - (void)doReadData
// STEP 1 - READ FROM PREBUFFER
//
- NSUInteger partialReadBufferLength = [partialReadBuffer length];
-
- if (partialReadBufferLength > 0)
+ if ([preBuffer availableBytes] > 0)
{
// There are 3 types of read packets:
//
@@ -4097,13 +4347,13 @@ - (void)doReadData
{
// Read type #3 - read up to a terminator
- bytesToCopy = [currentRead readLengthForTermWithPreBuffer:partialReadBuffer found:&done];
+ bytesToCopy = [currentRead readLengthForTermWithPreBuffer:preBuffer found:&done];
}
else
{
// Read type #1 or #2
- bytesToCopy = [currentRead readLengthForNonTermWithHint:partialReadBufferLength];
+ bytesToCopy = [currentRead readLengthForNonTermWithHint:[preBuffer availableBytes]];
}
// Make sure we have enough room in the buffer for our read.
@@ -4115,13 +4365,12 @@ - (void)doReadData
uint8_t *buffer = (uint8_t *)[currentRead->buffer mutableBytes] + currentRead->startOffset +
currentRead->bytesDone;
- memcpy(buffer, [partialReadBuffer bytes], bytesToCopy);
+ memcpy(buffer, [preBuffer readBuffer], bytesToCopy);
- // Remove the copied bytes from the partial read buffer
- [partialReadBuffer replaceBytesInRange:NSMakeRange(0, bytesToCopy) withBytes:NULL length:0];
- partialReadBufferLength -= bytesToCopy;
+ // Remove the copied bytes from the preBuffer
+ [preBuffer didRead:bytesToCopy];
- LogVerbose(@"copied(%lu) partialReadBufferLength(%lu)", bytesToCopy, partialReadBufferLength);
+ LogVerbose(@"copied(%lu) preBufferLength(%zu)", (unsigned long)bytesToCopy, [preBuffer availableBytes]);
// Update totals
@@ -4175,7 +4424,7 @@ - (void)doReadData
if (!done && !error && !socketEOF && !waiting && hasBytesAvailable)
{
- NSAssert((partialReadBufferLength == 0), @"Invalid logic");
+ NSAssert(([preBuffer availableBytes] == 0), @"Invalid logic");
// There are 3 types of read packets:
//
@@ -4183,7 +4432,7 @@ - (void)doReadData
// 2) Read a specific length of data.
// 3) Read up to a particular terminator.
- BOOL readIntoPartialReadBuffer = NO;
+ BOOL readIntoPreBuffer = NO;
NSUInteger bytesToRead;
if ([self usingCFStreamForTLS])
@@ -4200,7 +4449,7 @@ - (void)doReadData
NSUInteger defaultReadLength = (1024 * 32);
bytesToRead = [currentRead optimalReadLengthWithDefault:defaultReadLength
- shouldPreBuffer:&readIntoPartialReadBuffer];
+ shouldPreBuffer:&readIntoPreBuffer];
}
else
{
@@ -4209,7 +4458,7 @@ - (void)doReadData
// Read type #3 - read up to a terminator
bytesToRead = [currentRead readLengthForTermWithHint:estimatedBytesAvailable
- shouldPreBuffer:&readIntoPartialReadBuffer];
+ shouldPreBuffer:&readIntoPreBuffer];
}
else
{
@@ -4227,18 +4476,15 @@ - (void)doReadData
// Make sure we have enough room in the buffer for our read.
//
// We are either reading directly into the currentRead->buffer,
- // or we're reading into the temporary partialReadBuffer.
+ // or we're reading into the temporary preBuffer.
uint8_t *buffer;
- if (readIntoPartialReadBuffer)
+ if (readIntoPreBuffer)
{
- if (bytesToRead > partialReadBufferLength)
- {
- [partialReadBuffer setLength:bytesToRead];
- }
-
- buffer = [partialReadBuffer mutableBytes];
+ [preBuffer ensureCapacityForWrite:bytesToRead];
+
+ buffer = [preBuffer writeBuffer];
}
else
{
@@ -4263,16 +4509,10 @@ - (void)doReadData
if (result < 0)
{
error = (__bridge_transfer NSError *)CFReadStreamCopyError(readStream);
-
- if (readIntoPartialReadBuffer)
- [partialReadBuffer setLength:0];
}
else if (result == 0)
{
socketEOF = YES;
-
- if (readIntoPartialReadBuffer)
- [partialReadBuffer setLength:0];
}
else
{
@@ -4319,18 +4559,26 @@ - (void)doReadData
if (result == errSSLWouldBlock)
waiting = YES;
else
- error = [self sslError:result];
-
- // It's possible that bytesRead > 0, yet the result is errSSLWouldBlock.
+ {
+ if (result == errSSLClosedGraceful || result == errSSLClosedAbort)
+ {
+ // We've reached the end of the stream.
+ // Handle this the same way we would an EOF from the socket.
+ socketEOF = YES;
+ sslErrCode = result;
+ }
+ else
+ {
+ error = [self sslError:result];
+ }
+ }
+ // It's possible that bytesRead > 0, even if the result was errSSLWouldBlock.
// This happens when the SSLRead function is able to read some data,
// but not the entire amount we requested.
if (bytesRead <= 0)
{
bytesRead = 0;
-
- if (readIntoPartialReadBuffer)
- [partialReadBuffer setLength:0];
}
}
@@ -4355,17 +4603,11 @@ - (void)doReadData
error = [self errnoErrorWithReason:@"Error in read() function"];
socketFDBytesAvailable = 0;
-
- if (readIntoPartialReadBuffer)
- [partialReadBuffer setLength:0];
}
else if (result == 0)
{
socketEOF = YES;
socketFDBytesAvailable = 0;
-
- if (readIntoPartialReadBuffer)
- [partialReadBuffer setLength:0];
}
else
{
@@ -4403,7 +4645,7 @@ - (void)doReadData
//
// Note: We should never be using a prebuffer when we're reading a specific length of data.
- NSAssert(readIntoPartialReadBuffer == NO, @"Invalid logic");
+ NSAssert(readIntoPreBuffer == NO, @"Invalid logic");
currentRead->bytesDone += bytesRead;
totalBytesReadForCurrentRead += bytesRead;
@@ -4414,18 +4656,17 @@ - (void)doReadData
{
// Read type #3 - read up to a terminator
- if (readIntoPartialReadBuffer)
+ if (readIntoPreBuffer)
{
- // We just read a big chunk of data into the partialReadBuffer.
- // Search for the terminating sequence.
- //
- // Note: We are depending upon [partialReadBuffer length] to tell us how much data is
- // available in the partialReadBuffer. So we need to be sure this matches how many bytes
- // have actually been read into said buffer.
+ // We just read a big chunk of data into the preBuffer
- [partialReadBuffer setLength:bytesRead];
+ [preBuffer didWrite:bytesRead];
+ LogVerbose(@"read data into preBuffer - preBuffer.length = %zu", [preBuffer availableBytes]);
- bytesToRead = [currentRead readLengthForTermWithPreBuffer:partialReadBuffer found:&done];
+ // Search for the terminating sequence
+
+ bytesToRead = [currentRead readLengthForTermWithPreBuffer:preBuffer found:&done];
+ LogVerbose(@"copying %lu bytes from preBuffer", (unsigned long)bytesToRead);
// Ensure there's room on the read packet's buffer
@@ -4433,14 +4674,14 @@ - (void)doReadData
// Copy bytes from prebuffer into read buffer
- uint8_t *preBuf = [partialReadBuffer mutableBytes];
uint8_t *readBuf = (uint8_t *)[currentRead->buffer mutableBytes] + currentRead->startOffset
- + currentRead->bytesDone;
+ + currentRead->bytesDone;
- memcpy(readBuf, preBuf, bytesToRead);
+ memcpy(readBuf, [preBuffer readBuffer], bytesToRead);
// Remove the copied bytes from the prebuffer
- [partialReadBuffer replaceBytesInRange:NSMakeRange(0, bytesToRead) withBytes:NULL length:0];
+ [preBuffer didRead:bytesToRead];
+ LogVerbose(@"preBuffer.length = %zu", [preBuffer availableBytes]);
// Update totals
currentRead->bytesDone += bytesToRead;
@@ -4473,10 +4714,16 @@ - (void)doReadData
NSInteger underflow = bytesRead - overflow;
- // Copy excess data into partialReadBuffer
- void *overflowBuffer = buffer + currentRead->bytesDone + underflow;
+ // Copy excess data into preBuffer
+
+ LogVerbose(@"copying %ld overflow bytes into preBuffer", (long)overflow);
+ [preBuffer ensureCapacityForWrite:overflow];
+
+ uint8_t *overflowBuffer = buffer + underflow;
+ memcpy([preBuffer writeBuffer], overflowBuffer, overflow);
- [partialReadBuffer appendBytes:overflowBuffer length:overflow];
+ [preBuffer didWrite:overflow];
+ LogVerbose(@"preBuffer.length = %zu", [preBuffer availableBytes]);
// Note: The completeCurrentRead method will trim the buffer for us.
@@ -4509,34 +4756,30 @@ - (void)doReadData
{
// Read type #1 - read all available data
- if (readIntoPartialReadBuffer)
+ if (readIntoPreBuffer)
{
- // We just read a chunk of data into the partialReadBuffer.
- // Copy the data into the read packet.
+ // We just read a chunk of data into the preBuffer
+
+ [preBuffer didWrite:bytesRead];
+
+ // Now copy the data into the read packet.
//
// Recall that we didn't read directly into the packet's buffer to avoid
// over-allocating memory since we had no clue how much data was available to be read.
//
- // Note: We are depending upon [partialReadBuffer length] to tell us how much data is
- // available in the partialReadBuffer. So we need to be sure this matches how many bytes
- // have actually been read into said buffer.
-
- [partialReadBuffer setLength:bytesRead];
-
// Ensure there's room on the read packet's buffer
[currentRead ensureCapacityForAdditionalDataOfLength:bytesRead];
// Copy bytes from prebuffer into read buffer
- uint8_t *preBuf = [partialReadBuffer mutableBytes];
uint8_t *readBuf = (uint8_t *)[currentRead->buffer mutableBytes] + currentRead->startOffset
- + currentRead->bytesDone;
+ + currentRead->bytesDone;
- memcpy(readBuf, preBuf, bytesRead);
+ memcpy(readBuf, [preBuffer readBuffer], bytesRead);
// Remove the copied bytes from the prebuffer
- [partialReadBuffer replaceBytesInRange:NSMakeRange(0, bytesRead) withBytes:NULL length:0];
+ [preBuffer didRead:bytesRead];
// Update totals
currentRead->bytesDone += bytesRead;
@@ -4571,7 +4814,7 @@ - (void)doReadData
{
[self completeCurrentRead];
- if (!error && (!socketEOF || partialReadBufferLength > 0))
+ if (!error && (!socketEOF || [preBuffer availableBytes] > 0))
{
[self maybeDequeueRead];
}
@@ -4583,11 +4826,11 @@ - (void)doReadData
if (delegateQueue && [delegate respondsToSelector:@selector(socket:didReadPartialDataOfLength:tag:)])
{
__strong id theDelegate = delegate;
- GCDAsyncReadPacket *theRead = currentRead;
+ long theReadTag = currentRead->tag;
dispatch_async(delegateQueue, ^{ @autoreleasepool {
- [theDelegate socket:self didReadPartialDataOfLength:totalBytesReadForCurrentRead tag:theRead->tag];
+ [theDelegate socket:self didReadPartialDataOfLength:totalBytesReadForCurrentRead tag:theReadTag];
}});
}
}
@@ -4619,14 +4862,14 @@ - (void)doReadEOF
LogTrace();
// This method may be called more than once.
- // If the EOF is read while there is still data in the partialReadBuffer,
+ // If the EOF is read while there is still data in the preBuffer,
// then this method may be called continually after invocations of doReadData to see if it's time to disconnect.
flags |= kSocketHasReadEOF;
if (flags & kSocketSecure)
{
- // If the SSL layer has any buffered data, flush it into the partialReadBuffer now.
+ // If the SSL layer has any buffered data, flush it into the preBuffer now.
[self flushSSLBuffers];
}
@@ -4650,7 +4893,7 @@ - (void)doReadEOF
}
else if (flags & kReadStreamClosed)
{
- // The partialReadBuffer has already been drained.
+ // The preBuffer has already been drained.
// The config allows half-duplex connections.
// We've previously checked the socket, and it appeared writeable.
// So we marked the read stream as closed and notified the delegate.
@@ -4660,7 +4903,7 @@ - (void)doReadEOF
shouldDisconnect = NO;
}
- else if ([partialReadBuffer length] > 0)
+ else if ([preBuffer availableBytes] > 0)
{
LogVerbose(@"Socket reached EOF, but there is still data available in prebuffer");
@@ -4720,7 +4963,23 @@ - (void)doReadEOF
{
if (error == nil)
{
- error = [self connectionClosedError];
+ if ([self usingSecureTransportForTLS])
+ {
+ #if SECURE_TRANSPORT_MAYBE_AVAILABLE
+ if (sslErrCode != noErr && sslErrCode != errSSLClosedGraceful)
+ {
+ error = [self sslError:sslErrCode];
+ }
+ else
+ {
+ error = [self connectionClosedError];
+ }
+ #endif
+ }
+ else
+ {
+ error = [self connectionClosedError];
+ }
}
[self closeWithError:error];
}
@@ -4809,11 +5068,13 @@ - (void)setupReadTimerWithTimeout:(NSTimeInterval)timeout
[self doReadTimeout];
}});
+ #if NEEDS_DISPATCH_RETAIN_RELEASE
dispatch_source_t theReadTimer = readTimer;
dispatch_source_set_cancel_handler(readTimer, ^{
LogVerbose(@"dispatch_release(readTimer)");
dispatch_release(theReadTimer);
});
+ #endif
dispatch_time_t tt = dispatch_time(DISPATCH_TIME_NOW, (timeout * NSEC_PER_SEC));
@@ -4906,6 +5167,43 @@ - (void)writeData:(NSData *)data withTimeout:(NSTimeInterval)timeout tag:(long)t
// as the queue might get released without the block completing.
}
+- (float)progressOfWriteReturningTag:(long *)tagPtr bytesDone:(NSUInteger *)donePtr total:(NSUInteger *)totalPtr
+{
+ __block float result = 0.0F;
+
+ dispatch_block_t block = ^{
+
+ if (!currentWrite || ![currentWrite isKindOfClass:[GCDAsyncWritePacket class]])
+ {
+ // We're not writing anything right now.
+
+ if (tagPtr != NULL) *tagPtr = 0;
+ if (donePtr != NULL) *donePtr = 0;
+ if (totalPtr != NULL) *totalPtr = 0;
+
+ result = NAN;
+ }
+ else
+ {
+ NSUInteger done = currentWrite->bytesDone;
+ NSUInteger total = [currentWrite->buffer length];
+
+ if (tagPtr != NULL) *tagPtr = currentWrite->tag;
+ if (donePtr != NULL) *donePtr = done;
+ if (totalPtr != NULL) *totalPtr = total;
+
+ result = (float)done / (float)total;
+ }
+ };
+
+ if (dispatch_get_current_queue() == socketQueue)
+ block();
+ else
+ dispatch_sync(socketQueue, block);
+
+ return result;
+}
+
/**
* Conditionally starts a new write.
*
@@ -5052,7 +5350,7 @@ - (void)doWriteData
return;
}
- // Note: This method is not called if theCurrentWrite is an GCDAsyncSpecialPacket (startTLS packet)
+ // Note: This method is not called if currentWrite is a GCDAsyncSpecialPacket (startTLS packet)
BOOL waiting = NO;
NSError *error = nil;
@@ -5337,11 +5635,11 @@ - (void)doWriteData
if (delegateQueue && [delegate respondsToSelector:@selector(socket:didWritePartialDataOfLength:tag:)])
{
__strong id theDelegate = delegate;
- GCDAsyncWritePacket *theWrite = currentWrite;
+ long theWriteTag = currentWrite->tag;
dispatch_async(delegateQueue, ^{ @autoreleasepool {
- [theDelegate socket:self didWritePartialDataOfLength:bytesWritten tag:theWrite->tag];
+ [theDelegate socket:self didWritePartialDataOfLength:bytesWritten tag:theWriteTag];
}});
}
}
@@ -5367,11 +5665,11 @@ - (void)completeCurrentWrite
if (delegateQueue && [delegate respondsToSelector:@selector(socket:didWriteDataWithTag:)])
{
__strong id theDelegate = delegate;
- GCDAsyncWritePacket *theWrite = currentWrite;
+ long theWriteTag = currentWrite->tag;
dispatch_async(delegateQueue, ^{ @autoreleasepool {
- [theDelegate socket:self didWriteDataWithTag:theWrite->tag];
+ [theDelegate socket:self didWriteDataWithTag:theWriteTag];
}});
}
@@ -5400,11 +5698,13 @@ - (void)setupWriteTimerWithTimeout:(NSTimeInterval)timeout
[self doWriteTimeout];
}});
+ #if NEEDS_DISPATCH_RETAIN_RELEASE
dispatch_source_t theWriteTimer = writeTimer;
dispatch_source_set_cancel_handler(writeTimer, ^{
LogVerbose(@"dispatch_release(writeTimer)");
dispatch_release(theWriteTimer);
});
+ #endif
dispatch_time_t tt = dispatch_time(DISPATCH_TIME_NOW, (timeout * NSEC_PER_SEC));
@@ -5573,7 +5873,7 @@ - (OSStatus)sslReadWithBuffer:(void *)buffer length:(size_t *)bufferLength
{
LogVerbose(@"sslReadWithBuffer:%p length:%lu", buffer, (unsigned long)*bufferLength);
- if ((socketFDBytesAvailable == 0) && ([sslReadBuffer length] == 0))
+ if ((socketFDBytesAvailable == 0) && ([sslPreBuffer availableBytes] == 0))
{
LogVerbose(@"%@ - No data available to read...", THIS_METHOD);
@@ -5598,25 +5898,24 @@ - (OSStatus)sslReadWithBuffer:(void *)buffer length:(size_t *)bufferLength
// STEP 1 : READ FROM SSL PRE BUFFER
//
- NSUInteger sslReadBufferLength = [sslReadBuffer length];
+ size_t sslPreBufferLength = [sslPreBuffer availableBytes];
- if (sslReadBufferLength > 0)
+ if (sslPreBufferLength > 0)
{
LogVerbose(@"%@: Reading from SSL pre buffer...", THIS_METHOD);
size_t bytesToCopy;
- if (sslReadBufferLength > totalBytesLeftToBeRead)
+ if (sslPreBufferLength > totalBytesLeftToBeRead)
bytesToCopy = totalBytesLeftToBeRead;
else
- bytesToCopy = (size_t)sslReadBufferLength;
-
- LogVerbose(@"%@: Copying %zu bytes from sslReadBuffer", THIS_METHOD, bytesToCopy);
+ bytesToCopy = sslPreBufferLength;
- memcpy(buffer, [sslReadBuffer mutableBytes], bytesToCopy);
+ LogVerbose(@"%@: Copying %zu bytes from sslPreBuffer", THIS_METHOD, bytesToCopy);
- [sslReadBuffer replaceBytesInRange:NSMakeRange(0, bytesToCopy) withBytes:NULL length:0];
+ memcpy(buffer, [sslPreBuffer readBuffer], bytesToCopy);
+ [sslPreBuffer didRead:bytesToCopy];
- LogVerbose(@"%@: sslReadBuffer.length = %lu", THIS_METHOD, (unsigned long)[sslReadBuffer length]);
+ LogVerbose(@"%@: sslPreBuffer.length = %zu", THIS_METHOD, [sslPreBuffer availableBytes]);
totalBytesRead += bytesToCopy;
totalBytesLeftToBeRead -= bytesToCopy;
@@ -5642,19 +5941,16 @@ - (OSStatus)sslReadWithBuffer:(void *)buffer length:(size_t *)bufferLength
if (socketFDBytesAvailable > totalBytesLeftToBeRead)
{
- // Read all available data from socket into sslReadBuffer.
+ // Read all available data from socket into sslPreBuffer.
// Then copy requested amount into dataBuffer.
- LogVerbose(@"%@: Reading into sslReadBuffer...", THIS_METHOD);
+ LogVerbose(@"%@: Reading into sslPreBuffer...", THIS_METHOD);
- if ([sslReadBuffer length] < socketFDBytesAvailable)
- {
- [sslReadBuffer setLength:socketFDBytesAvailable];
- }
+ [sslPreBuffer ensureCapacityForWrite:socketFDBytesAvailable];
readIntoPreBuffer = YES;
bytesToRead = (size_t)socketFDBytesAvailable;
- buf = [sslReadBuffer mutableBytes];
+ buf = [sslPreBuffer writeBuffer];
}
else
{
@@ -5680,11 +5976,6 @@ - (OSStatus)sslReadWithBuffer:(void *)buffer length:(size_t *)bufferLength
}
socketFDBytesAvailable = 0;
-
- if (readIntoPreBuffer)
- {
- [sslReadBuffer setLength:0];
- }
}
else if (result == 0)
{
@@ -5692,11 +5983,6 @@ - (OSStatus)sslReadWithBuffer:(void *)buffer length:(size_t *)bufferLength
socketError = YES;
socketFDBytesAvailable = 0;
-
- if (readIntoPreBuffer)
- {
- [sslReadBuffer setLength:0];
- }
}
else
{
@@ -5709,19 +5995,19 @@ - (OSStatus)sslReadWithBuffer:(void *)buffer length:(size_t *)bufferLength
if (readIntoPreBuffer)
{
- size_t bytesToCopy = MIN(totalBytesLeftToBeRead, bytesReadFromSocket);
+ [sslPreBuffer didWrite:bytesReadFromSocket];
- LogVerbose(@"%@: Copying %zu bytes out of sslReadBuffer", THIS_METHOD, bytesToCopy);
+ size_t bytesToCopy = MIN(totalBytesLeftToBeRead, bytesReadFromSocket);
- memcpy((uint8_t *)buffer + totalBytesRead, [sslReadBuffer bytes], bytesToCopy);
+ LogVerbose(@"%@: Copying %zu bytes out of sslPreBuffer", THIS_METHOD, bytesToCopy);
- [sslReadBuffer setLength:bytesReadFromSocket];
- [sslReadBuffer replaceBytesInRange:NSMakeRange(0, bytesToCopy) withBytes:NULL length:0];
+ memcpy((uint8_t *)buffer + totalBytesRead, [sslPreBuffer readBuffer], bytesToCopy);
+ [sslPreBuffer didRead:bytesToCopy];
totalBytesRead += bytesToCopy;
totalBytesLeftToBeRead -= bytesToCopy;
- LogVerbose(@"%@: sslReadBuffer.length = %lu", THIS_METHOD, (unsigned long)[sslReadBuffer length]);
+ LogVerbose(@"%@: sslPreBuffer.length = %zu", THIS_METHOD, [sslPreBuffer availableBytes]);
}
else
{
@@ -6171,20 +6457,26 @@ - (void)ssl_startTLS
}
#endif
- // Setup the sslReadBuffer
+ // Setup the sslPreBuffer
//
- // If there is any data in the partialReadBuffer,
- // this needs to be moved into the sslReadBuffer,
+ // Any data in the preBuffer needs to be moved into the sslPreBuffer,
// as this data is now part of the secure read stream.
- sslReadBuffer = [[NSMutableData alloc] init];
+ sslPreBuffer = [[GCDAsyncSocketPreBuffer alloc] initWithCapacity:(1024 * 4)];
+
+ size_t preBufferLength = [preBuffer availableBytes];
- if ([partialReadBuffer length] > 0)
+ if (preBufferLength > 0)
{
- [sslReadBuffer appendData:partialReadBuffer];
- [partialReadBuffer setLength:0];
+ [sslPreBuffer ensureCapacityForWrite:preBufferLength];
+
+ memcpy([sslPreBuffer writeBuffer], [preBuffer readBuffer], preBufferLength);
+ [preBuffer didRead:preBufferLength];
+ [sslPreBuffer didWrite:preBufferLength];
}
+ sslErrCode = noErr;
+
// Start the SSL Handshake process
[self ssl_continueSSLHandshake];
@@ -6295,7 +6587,7 @@ - (void)cf_startTLS
LogVerbose(@"Starting TLS (via CFStream)...");
- if ([partialReadBuffer length] > 0)
+ if ([preBuffer availableBytes] > 0)
{
NSString *msg = @"Invalid TLS transition. Handshake has already been read from socket.";
@@ -6406,7 +6698,7 @@ + (void)cfstreamThread { @autoreleasepool
// So we'll just create a timer that will never fire - unless the server runs for decades.
[NSTimer scheduledTimerWithTimeInterval:[[NSDate distantFuture] timeIntervalSinceNow]
target:self
- selector:@selector(ignore:)
+ selector:@selector(doNothingAtAll:)
userInfo:nil
repeats:YES];

0 comments on commit 4972df6

Please sign in to comment.
Something went wrong with that request. Please try again.