diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..b3dbff00 --- /dev/null +++ b/LICENSE @@ -0,0 +1,22 @@ +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. + +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. diff --git a/SuperSocket/SuperSocket.xcodeproj/project.pbxproj b/SuperSocket.xcodeproj/project.pbxproj similarity index 96% rename from SuperSocket/SuperSocket.xcodeproj/project.pbxproj rename to SuperSocket.xcodeproj/project.pbxproj index 67786dfa..24e132fc 100644 --- a/SuperSocket/SuperSocket.xcodeproj/project.pbxproj +++ b/SuperSocket.xcodeproj/project.pbxproj @@ -7,12 +7,13 @@ objects = { /* Begin PBXBuildFile section */ + 5D1DC7F81B754B6100236EE6 /* STCPSpecialPacket.h in Headers */ = {isa = PBXBuildFile; fileRef = 5D1DC7F61B754B6100236EE6 /* STCPSpecialPacket.h */; }; + 5D1DC7F91B754B6100236EE6 /* STCPSpecialPacket.m in Sources */ = {isa = PBXBuildFile; fileRef = 5D1DC7F71B754B6100236EE6 /* STCPSpecialPacket.m */; }; 5D77F99A1B5597510013F9A7 /* STCPSocket.h in Headers */ = {isa = PBXBuildFile; fileRef = 5D77F9951B5597510013F9A7 /* STCPSocket.h */; settings = {ATTRIBUTES = (Public, ); }; }; 5D77F99B1B5597510013F9A7 /* STCPSocket.m in Sources */ = {isa = PBXBuildFile; fileRef = 5D77F9961B5597510013F9A7 /* STCPSocket.m */; }; 5D77F99C1B5597510013F9A7 /* SUDPSocket.h in Headers */ = {isa = PBXBuildFile; fileRef = 5D77F9971B5597510013F9A7 /* SUDPSocket.h */; settings = {ATTRIBUTES = (Public, ); }; }; 5D77F99D1B5597510013F9A7 /* SUDPSocket.m in Sources */ = {isa = PBXBuildFile; fileRef = 5D77F9981B5597510013F9A7 /* SUDPSocket.m */; }; 5D77F99E1B5597510013F9A7 /* SuperSocket.h in Headers */ = {isa = PBXBuildFile; fileRef = 5D77F9991B5597510013F9A7 /* SuperSocket.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 5D77F9A01B55976D0013F9A7 /* Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 5D77F99F1B55976D0013F9A7 /* Info.plist */; }; 5D77F9AB1B55992D0013F9A7 /* SuperSocketTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 5D77F9AA1B55992D0013F9A7 /* SuperSocketTests.m */; }; 5D77F9AD1B55992D0013F9A7 /* SuperSocket.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5D48330A1A9D074D00252386 /* SuperSocket.framework */; }; 5D77F9B61B559FF90013F9A7 /* SUDPSendPacket.h in Headers */ = {isa = PBXBuildFile; fileRef = 5D77F9B41B559FF90013F9A7 /* SUDPSendPacket.h */; }; @@ -25,8 +26,6 @@ 5D77F9C41B55A10B0013F9A7 /* STCPReadPacket.m in Sources */ = {isa = PBXBuildFile; fileRef = 5D77F9C21B55A10B0013F9A7 /* STCPReadPacket.m */; }; 5D77F9C71B55A13A0013F9A7 /* STCPWritePacket.h in Headers */ = {isa = PBXBuildFile; fileRef = 5D77F9C51B55A13A0013F9A7 /* STCPWritePacket.h */; }; 5D77F9C81B55A13A0013F9A7 /* STCPWritePacket.m in Sources */ = {isa = PBXBuildFile; fileRef = 5D77F9C61B55A13A0013F9A7 /* STCPWritePacket.m */; }; - 5D77F9CB1B55A1750013F9A7 /* STCPSpecialPacket.h in Headers */ = {isa = PBXBuildFile; fileRef = 5D77F9C91B55A1750013F9A7 /* STCPSpecialPacket.h */; }; - 5D77F9CC1B55A1750013F9A7 /* STCPSpecialPacket.m in Sources */ = {isa = PBXBuildFile; fileRef = 5D77F9CA1B55A1750013F9A7 /* STCPSpecialPacket.m */; }; 5D77F9CF1B55A8B30013F9A7 /* STCPSocketDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 5D77F9CE1B55A8B30013F9A7 /* STCPSocketDelegate.h */; settings = {ATTRIBUTES = (Public, ); }; }; 5D77F9D21B55AAD80013F9A7 /* SUDPSocketDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 5D77F9D11B55AAD80013F9A7 /* SUDPSocketDelegate.h */; settings = {ATTRIBUTES = (Public, ); }; }; /* End PBXBuildFile section */ @@ -42,6 +41,8 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ + 5D1DC7F61B754B6100236EE6 /* STCPSpecialPacket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = STCPSpecialPacket.h; path = SuperSocket/STCPSpecialPacket.h; sourceTree = SOURCE_ROOT; }; + 5D1DC7F71B754B6100236EE6 /* STCPSpecialPacket.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = STCPSpecialPacket.m; path = SuperSocket/STCPSpecialPacket.m; sourceTree = SOURCE_ROOT; }; 5D48330A1A9D074D00252386 /* SuperSocket.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SuperSocket.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 5D77F9951B5597510013F9A7 /* STCPSocket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = STCPSocket.h; path = SuperSocket/STCPSocket.h; sourceTree = SOURCE_ROOT; }; 5D77F9961B5597510013F9A7 /* STCPSocket.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = STCPSocket.m; path = SuperSocket/STCPSocket.m; sourceTree = SOURCE_ROOT; }; @@ -62,8 +63,6 @@ 5D77F9C21B55A10B0013F9A7 /* STCPReadPacket.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = STCPReadPacket.m; path = SuperSocket/STCPReadPacket.m; sourceTree = SOURCE_ROOT; }; 5D77F9C51B55A13A0013F9A7 /* STCPWritePacket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = STCPWritePacket.h; path = SuperSocket/STCPWritePacket.h; sourceTree = SOURCE_ROOT; }; 5D77F9C61B55A13A0013F9A7 /* STCPWritePacket.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = STCPWritePacket.m; path = SuperSocket/STCPWritePacket.m; sourceTree = SOURCE_ROOT; }; - 5D77F9C91B55A1750013F9A7 /* STCPSpecialPacket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = STCPSpecialPacket.h; sourceTree = SOURCE_ROOT; }; - 5D77F9CA1B55A1750013F9A7 /* STCPSpecialPacket.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = STCPSpecialPacket.m; sourceTree = SOURCE_ROOT; }; 5D77F9CE1B55A8B30013F9A7 /* STCPSocketDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = STCPSocketDelegate.h; path = SuperSocket/STCPSocketDelegate.h; sourceTree = SOURCE_ROOT; }; 5D77F9D11B55AAD80013F9A7 /* SUDPSocketDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SUDPSocketDelegate.h; path = SuperSocket/SUDPSocketDelegate.h; sourceTree = SOURCE_ROOT; }; /* End PBXFileReference section */ @@ -165,8 +164,8 @@ 5D77F9C21B55A10B0013F9A7 /* STCPReadPacket.m */, 5D77F9C51B55A13A0013F9A7 /* STCPWritePacket.h */, 5D77F9C61B55A13A0013F9A7 /* STCPWritePacket.m */, - 5D77F9C91B55A1750013F9A7 /* STCPSpecialPacket.h */, - 5D77F9CA1B55A1750013F9A7 /* STCPSpecialPacket.m */, + 5D1DC7F61B754B6100236EE6 /* STCPSpecialPacket.h */, + 5D1DC7F71B754B6100236EE6 /* STCPSpecialPacket.m */, ); name = Internal; sourceTree = ""; @@ -195,8 +194,8 @@ 5D77F9BA1B55A0690013F9A7 /* SUDPSpecialPacket.h in Headers */, 5D77F9BF1B55A0CC0013F9A7 /* STCPSocketPreBuffer.h in Headers */, 5D77F9C71B55A13A0013F9A7 /* STCPWritePacket.h in Headers */, - 5D77F9CB1B55A1750013F9A7 /* STCPSpecialPacket.h in Headers */, 5D77F99A1B5597510013F9A7 /* STCPSocket.h in Headers */, + 5D1DC7F81B754B6100236EE6 /* STCPSpecialPacket.h in Headers */, 5D77F9C31B55A10B0013F9A7 /* STCPReadPacket.h in Headers */, 5D77F9CF1B55A8B30013F9A7 /* STCPSocketDelegate.h in Headers */, 5D77F99C1B5597510013F9A7 /* SUDPSocket.h in Headers */, @@ -282,7 +281,6 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - 5D77F9A01B55976D0013F9A7 /* Info.plist in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -301,7 +299,7 @@ buildActionMask = 2147483647; files = ( 5D77F99D1B5597510013F9A7 /* SUDPSocket.m in Sources */, - 5D77F9CC1B55A1750013F9A7 /* STCPSpecialPacket.m in Sources */, + 5D1DC7F91B754B6100236EE6 /* STCPSpecialPacket.m in Sources */, 5D77F99B1B5597510013F9A7 /* STCPSocket.m in Sources */, 5D77F9B71B559FF90013F9A7 /* SUDPSendPacket.m in Sources */, 5D77F9C41B55A10B0013F9A7 /* STCPReadPacket.m in Sources */, diff --git a/SuperSocket/SuperSocket.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/SuperSocket.xcodeproj/project.xcworkspace/contents.xcworkspacedata similarity index 100% rename from SuperSocket/SuperSocket.xcodeproj/project.xcworkspace/contents.xcworkspacedata rename to SuperSocket.xcodeproj/project.xcworkspace/contents.xcworkspacedata diff --git a/SuperSocket/SuperSocket.xcodeproj/xcshareddata/xcschemes/SuperSocket-Release.xcscheme b/SuperSocket.xcodeproj/xcshareddata/xcschemes/SuperSocket-Release.xcscheme similarity index 100% rename from SuperSocket/SuperSocket.xcodeproj/xcshareddata/xcschemes/SuperSocket-Release.xcscheme rename to SuperSocket.xcodeproj/xcshareddata/xcschemes/SuperSocket-Release.xcscheme diff --git a/SuperSocket/SuperSocket/Info.plist b/SuperSocket/Info.plist similarity index 97% rename from SuperSocket/SuperSocket/Info.plist rename to SuperSocket/Info.plist index b038301b..e4370ca6 100644 --- a/SuperSocket/SuperSocket/Info.plist +++ b/SuperSocket/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 7.5.0 + 8.1.0 CFBundleSignature ???? CFBundleVersion diff --git a/SuperSocket/SuperSocket/STCPReadPacket.h b/SuperSocket/STCPReadPacket.h similarity index 99% rename from SuperSocket/SuperSocket/STCPReadPacket.h rename to SuperSocket/STCPReadPacket.h index 4a19ae42..3db6c6d6 100644 --- a/SuperSocket/SuperSocket/STCPReadPacket.h +++ b/SuperSocket/STCPReadPacket.h @@ -18,7 +18,7 @@ * - or simply reading the first chunk of available data **/ @interface STCPReadPacket : NSObject { -@public + @public NSMutableData *buffer; NSUInteger startOffset; NSUInteger bytesDone; diff --git a/SuperSocket/SuperSocket/STCPReadPacket.m b/SuperSocket/STCPReadPacket.m similarity index 96% rename from SuperSocket/SuperSocket/STCPReadPacket.m rename to SuperSocket/STCPReadPacket.m index f285e41e..917e501a 100644 --- a/SuperSocket/SuperSocket/STCPReadPacket.m +++ b/SuperSocket/STCPReadPacket.m @@ -27,7 +27,7 @@ - (instancetype)initWithData:(NSMutableData *)d readLength = l; term = [e copy]; tag = i; - + if (d) { buffer = d; startOffset = s; @@ -38,7 +38,7 @@ - (instancetype)initWithData:(NSMutableData *)d buffer = [[NSMutableData alloc] initWithLength:readLength]; else buffer = [[NSMutableData alloc] initWithLength:0]; - + startOffset = 0; bufferOwner = YES; originalBufferLength = 0; @@ -53,12 +53,12 @@ - (instancetype)initWithData:(NSMutableData *)d - (void)ensureCapacityForAdditionalDataOfLength:(NSUInteger)bytesToRead { NSUInteger buffSize = [buffer length]; NSUInteger buffUsed = startOffset + bytesDone; - + NSUInteger buffSpace = buffSize - buffUsed; - + if (bytesToRead > buffSpace) { NSUInteger buffInc = bytesToRead - buffSpace; - + [buffer increaseLengthBy:buffInc]; } } @@ -72,16 +72,16 @@ - (void)ensureCapacityForAdditionalDataOfLength:(NSUInteger)bytesToRead { **/ - (NSUInteger)optimalReadLengthWithDefault:(NSUInteger)defaultValue shouldPreBuffer:(BOOL *)shouldPreBufferPtr { NSUInteger result; - + if (readLength > 0) { // Read a specific length of data - + result = MIN(defaultValue, (readLength - bytesDone)); - + // There is no need to prebuffer since we know exactly how much data we need to read. // Even if the buffer isn't currently big enough to fit this amount of data, // it would have to be resized eventually anyway. - + if (shouldPreBufferPtr) *shouldPreBufferPtr = NO; } else { @@ -92,32 +92,32 @@ - (NSUInteger)optimalReadLengthWithDefault:(NSUInteger)defaultValue shouldPreBuf // // - readDataToData packet // - readDataWithTimeout packet - + if (maxLength > 0) result = MIN(defaultValue, (maxLength - bytesDone)); else result = defaultValue; - + // Since we don't know the size of the read in advance, // the shouldPreBuffer decision is based upon whether the returned value would fit // in the current buffer without requiring a resize of the buffer. // // This is because, in all likelyhood, the amount read from the socket will be less than the default value. // Thus we should avoid over-allocating the read buffer when we can simply use the pre-buffer instead. - + if (shouldPreBufferPtr) { NSUInteger buffSize = [buffer length]; NSUInteger buffUsed = startOffset + bytesDone; - + NSUInteger buffSpace = buffSize - buffUsed; - + if (buffSpace >= result) *shouldPreBufferPtr = NO; else *shouldPreBufferPtr = YES; } } - + return result; } @@ -133,12 +133,12 @@ - (NSUInteger)optimalReadLengthWithDefault:(NSUInteger)defaultValue shouldPreBuf - (NSUInteger)readLengthForNonTermWithHint:(NSUInteger)bytesAvailable { NSAssert(term == nil, @"This method does not apply to term reads"); NSAssert(bytesAvailable > 0, @"Invalid parameter: bytesAvailable"); - + if (readLength > 0) { // Read a specific length of data - + return MIN(bytesAvailable, (readLength - bytesDone)); - + // No need to avoid resizing the buffer. // If the user provided their own buffer, // and told us to read a certain length of data that exceeds the size of the buffer, @@ -148,13 +148,13 @@ - (NSUInteger)readLengthForNonTermWithHint:(NSUInteger)bytesAvailable { // The resizing will happen elsewhere if needed. } else { // Read all available data - + NSUInteger result = bytesAvailable; - + if (maxLength > 0) { result = MIN(result, (maxLength - bytesDone)); } - + // No need to avoid resizing the buffer. // If the user provided their own buffer, // and told us to read all available data without giving us a maxLength, @@ -162,7 +162,7 @@ - (NSUInteger)readLengthForNonTermWithHint:(NSUInteger)bytesAvailable { // // This method does not actually do any resizing. // The resizing will happen elsewhere if needed. - + return result; } } @@ -181,14 +181,14 @@ - (NSUInteger)readLengthForNonTermWithHint:(NSUInteger)bytesAvailable { - (NSUInteger)readLengthForTermWithHint:(NSUInteger)bytesAvailable shouldPreBuffer:(BOOL *)shouldPreBufferPtr { NSAssert(term != nil, @"This method does not apply to non-term reads"); NSAssert(bytesAvailable > 0, @"Invalid parameter: bytesAvailable"); - - + + NSUInteger result = bytesAvailable; - + if (maxLength > 0) { result = MIN(result, (maxLength - bytesDone)); } - + // Should the data be read into the read packet's buffer, or into a pre-buffer first? // // One would imagine the preferred option is the faster one. @@ -228,17 +228,17 @@ - (NSUInteger)readLengthForTermWithHint:(NSUInteger)bytesAvailable shouldPreBuff // // If we can read all the data directly into the packet's buffer without resizing it first, // then we do so. Otherwise we use the prebuffer. - + if (shouldPreBufferPtr) { NSUInteger buffSize = [buffer length]; NSUInteger buffUsed = startOffset + bytesDone; - + if ((buffSize - buffUsed) >= result) *shouldPreBufferPtr = NO; else *shouldPreBufferPtr = YES; } - + return result; } @@ -252,7 +252,7 @@ - (NSUInteger)readLengthForTermWithHint:(NSUInteger)bytesAvailable shouldPreBuff - (NSUInteger)readLengthForTermWithPreBuffer:(STCPSocketPreBuffer *)preBuffer found:(BOOL *)foundPtr { NSAssert(term != nil, @"This method does not apply to non-term reads"); 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. // So we're going to look for the terminator starting with a portion of our own buffer. @@ -287,73 +287,73 @@ - (NSUInteger)readLengthForTermWithPreBuffer:(STCPSocketPreBuffer *)preBuffer fo // --------------------- // |B|B|B|B|B|P|P|P|P|P| // ---------------^-^-^- - + BOOL found = NO; - + NSUInteger termLength = [term length]; NSUInteger preBufferLength = [preBuffer availableBytes]; - + if ((bytesDone + preBufferLength) < termLength) { // Not enough data for a full term sequence yet return preBufferLength; } - + NSUInteger maxPreBufferLength; if (maxLength > 0) { maxPreBufferLength = MIN(preBufferLength, (maxLength - bytesDone)); - + // Note: maxLength >= termLength } else { maxPreBufferLength = preBufferLength; } - + uint8_t seq[termLength]; const void *termBuf = [term bytes]; - + NSUInteger bufLen = MIN(bytesDone, (termLength - 1)); uint8_t *buf = (uint8_t *)[buffer mutableBytes] + startOffset + bytesDone - bufLen; - + NSUInteger preLen = termLength - bufLen; const uint8_t *pre = [preBuffer readBuffer]; - + NSUInteger loopCount = bufLen + maxPreBufferLength - termLength + 1; // Plus one. See example above. - + NSUInteger result = maxPreBufferLength; - + NSUInteger i; for (i = 0; i < loopCount; i++) { if (bufLen > 0) { // Combining bytes from buffer and preBuffer - + memcpy(seq, buf, bufLen); memcpy(seq + bufLen, pre, preLen); - + if (memcmp(seq, termBuf, termLength) == 0) { result = preLen; found = YES; break; } - + buf++; bufLen--; preLen++; } else { // Comparing directly from preBuffer - + if (memcmp(pre, termBuf, termLength) == 0) { NSUInteger preOffset = pre - [preBuffer readBuffer]; // pointer arithmetic - + result = preOffset + termLength; found = YES; break; } - + pre++; } } - + // There is no need to avoid resizing the buffer in this particular situation. - + if (foundPtr) *foundPtr = found; return result; @@ -374,31 +374,31 @@ - (NSUInteger)readLengthForTermWithPreBuffer:(STCPSocketPreBuffer *)preBuffer fo **/ - (NSInteger)searchForTermAfterPreBuffering:(ssize_t)numBytes { NSAssert(term != nil, @"This method does not apply to non-term reads"); - + // The implementation of this method is very similar to the above method. // See the above method for a discussion of the algorithm used here. - + uint8_t *buff = [buffer mutableBytes]; NSUInteger buffLength = bytesDone + numBytes; - + const void *termBuff = [term bytes]; NSUInteger termLength = [term length]; - + // Note: We are dealing with unsigned integers, // so make sure the math doesn't go below zero. - + NSUInteger i = ((buffLength - numBytes) >= termLength) ? (buffLength - numBytes - termLength + 1) : 0; - + while (i + termLength <= buffLength) { uint8_t *subBuffer = buff + startOffset + i; - + if (memcmp(subBuffer, termBuff, termLength) == 0) { return buffLength - (i + termLength); } - + i++; } - + return -1; } diff --git a/SuperSocket/SuperSocket/STCPSocket.h b/SuperSocket/STCPSocket.h similarity index 99% rename from SuperSocket/SuperSocket/STCPSocket.h rename to SuperSocket/STCPSocket.h index 283dc796..670b957c 100644 --- a/SuperSocket/SuperSocket/STCPSocket.h +++ b/SuperSocket/STCPSocket.h @@ -1015,5 +1015,3 @@ typedef NS_ENUM(NSUInteger, STCPSocketError) { + (NSData *)ZeroData; // 0x00 @end - - diff --git a/SuperSocket/SuperSocket/STCPSocket.m b/SuperSocket/STCPSocket.m similarity index 97% rename from SuperSocket/SuperSocket/STCPSocket.m rename to SuperSocket/STCPSocket.m index c8c1089b..0de3a358 100644 --- a/SuperSocket/SuperSocket/STCPSocket.m +++ b/SuperSocket/STCPSocket.m @@ -113,14 +113,14 @@ * Seeing a return statements within an inner block * can sometimes be mistaken for a return point of the enclosing method. * This makes inline blocks a bit easier to read. -**/ + **/ #define return_from_block return /** * A socket file descriptor is really just an integer. * It represents the index of the socket within the kernel. * This makes invalid file descriptor comparisons easier to read. -**/ + **/ #define SOCKET_NULL -1 @@ -228,6 +228,7 @@ @implementation STCPSocket { STCPSocketPreBuffer *sslPreBuffer; size_t sslWriteCachedLength; OSStatus sslErrCode; + OSStatus lastSSLHandshakeError; void *IsOnSocketQueueOrTargetQueueKey; @@ -251,11 +252,6 @@ - (instancetype)initWithDelegate:(id)aDelegate delegateQueue delegate = aDelegate; delegateQueue = dq; -#if !OS_OBJECT_USE_OBJC - if (dq) - dispatch_retain(dq); -#endif - socket4FD = SOCKET_NULL; socket6FD = SOCKET_NULL; stateIndex = 0; @@ -269,9 +265,6 @@ - (instancetype)initWithDelegate:(id)aDelegate delegateQueue @"The given socketQueue parameter must not be a concurrent queue."); socketQueue = sq; -#if !OS_OBJECT_USE_OBJC - dispatch_retain(sq); -#endif } else { socketQueue = dispatch_queue_create([STCPSocketQueueName UTF8String], NULL); } @@ -325,17 +318,7 @@ - (void)dealloc { } delegate = nil; - -#if !OS_OBJECT_USE_OBJC - if (delegateQueue) - dispatch_release(delegateQueue); -#endif delegateQueue = NULL; - -#if !OS_OBJECT_USE_OBJC - if (socketQueue) - dispatch_release(socketQueue); -#endif socketQueue = NULL; LogInfo(@"%@ - %@ (finish)", THIS_METHOD, self); @@ -398,14 +381,6 @@ - (dispatch_queue_t)delegateQueue { - (void)setDelegateQueue:(dispatch_queue_t)newDelegateQueue synchronously:(BOOL)synchronously { dispatch_block_t block = ^{ - -#if !OS_OBJECT_USE_OBJC - if (delegateQueue) - dispatch_release(delegateQueue); - if (newDelegateQueue) - dispatch_retain(newDelegateQueue); -#endif - delegateQueue = newDelegateQueue; }; @@ -451,16 +426,7 @@ - (void)getDelegate:(id *)delegatePtr delegateQueue:(dispatc - (void)setDelegate:(id)newDelegate delegateQueue:(dispatch_queue_t)newDelegateQueue synchronously:(BOOL)synchronously { dispatch_block_t block = ^{ - delegate = newDelegate; - -#if !OS_OBJECT_USE_OBJC - if (delegateQueue) - dispatch_release(delegateQueue); - if (newDelegateQueue) - dispatch_retain(newDelegateQueue); -#endif - delegateQueue = newDelegateQueue; }; @@ -836,18 +802,8 @@ - (BOOL)acceptOnInterface:(NSString *)inInterface port:(uint16_t)port error:(NSE dispatch_source_set_cancel_handler(accept4Source, ^{ -#pragma clang diagnostic push -#pragma clang diagnostic warning "-Wimplicit-retain-self" - -#if !OS_OBJECT_USE_OBJC - LogVerbose(@"dispatch_release(accept4Source)"); - dispatch_release(acceptSource); -#endif - LogVerbose(@"close(socket4FD)"); close(socketFD); - -#pragma clang diagnostic pop }); LogVerbose(@"dispatch_resume(accept4Source)"); @@ -864,11 +820,10 @@ - (BOOL)acceptOnInterface:(NSString *)inInterface port:(uint16_t)port error:(NSE dispatch_source_set_event_handler(accept6Source, ^{ @autoreleasepool { -#pragma clang diagnostic push -#pragma clang diagnostic warning "-Wimplicit-retain-self" __strong STCPSocket *strongSelf = weakSelf; - if (strongSelf == nil) + if (strongSelf == nil) { return_from_block; + } LogVerbose(@"event6Block"); @@ -879,24 +834,13 @@ - (BOOL)acceptOnInterface:(NSString *)inInterface port:(uint16_t)port error:(NSE while ([strongSelf doAccept:socketFD] && (++i < numPendingConnections)) ; - -#pragma clang diagnostic pop } }); dispatch_source_set_cancel_handler(accept6Source, ^{ -#pragma clang diagnostic push -#pragma clang diagnostic warning "-Wimplicit-retain-self" - -#if !OS_OBJECT_USE_OBJC - LogVerbose(@"dispatch_release(accept6Source)"); - dispatch_release(acceptSource); -#endif LogVerbose(@"close(socket6FD)"); close(socketFD); - -#pragma clang diagnostic pop }); LogVerbose(@"dispatch_resume(accept6Source)"); @@ -909,10 +853,11 @@ - (BOOL)acceptOnInterface:(NSString *)inInterface port:(uint16_t)port error:(NSE } }; - if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) + if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) { block(); - else + } else { dispatch_sync(socketQueue, block); + } if (result == NO) { LogInfo(@"Error in accept: %@", err); @@ -978,7 +923,7 @@ - (BOOL)doAccept:(int)parentSocketFD { // Notify delegate if (delegateQueue) { - __strong id theDelegate = delegate; + __strong id theDelegate = delegate; dispatch_async(delegateQueue, ^{ @autoreleasepool { @@ -1013,17 +958,10 @@ - (BOOL)doAccept:(int)parentSocketFD { }); // Notify delegate - if ([theDelegate respondsToSelector:@selector(socket:didAcceptNewSocket:)]) { [theDelegate socket:self didAcceptNewSocket:acceptedSocket]; } -// Release the socket queue returned from the delegate (it was retained by acceptedSocket) -#if !OS_OBJECT_USE_OBJC - 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. } @@ -1033,20 +971,19 @@ - (BOOL)doAccept:(int)parentSocketFD { return YES; } -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + #pragma mark Connecting -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * This method runs through the various checks required prior to a connection attempt. * It is shared between the connectToHost and connectToAddress methods. - * -**/ + * + **/ - (BOOL)preConnectWithInterface:(NSString *)interface error:(NSError **)errPtr { NSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @"Must be dispatched on socketQueue"); - if (delegate == nil) // Must have delegate set - { + // Must have delegate set + if (delegate == nil) { if (errPtr) { NSString *msg = @"Attempting to connect without a delegate. Set a delegate first."; *errPtr = [self badConfigError:msg]; @@ -1186,14 +1123,13 @@ - (BOOL)connectToHost:(NSString *)inHost dispatch_queue_t globalConcurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_async(globalConcurrentQueue, ^{ @autoreleasepool { -#pragma clang diagnostic push -#pragma clang diagnostic warning "-Wimplicit-retain-self" NSError *lookupErr = nil; NSMutableArray *addresses = [STCPSocket lookupHost:hostCpy port:port error:&lookupErr]; __strong STCPSocket *strongSelf = weakSelf; - if (strongSelf == nil) + if (strongSelf == nil) { return_from_block; + } if (lookupErr) { dispatch_async(strongSelf->socketQueue, ^{ @@ -1219,8 +1155,6 @@ - (BOOL)connectToHost:(NSString *)inHost } }); } - -#pragma clang diagnostic pop } }); @@ -1230,14 +1164,17 @@ - (BOOL)connectToHost:(NSString *)inHost } }; - if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) + if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) { block(); - else + } else { dispatch_sync(socketQueue, block); + } - if (errPtr) + if (errPtr) { *errPtr = preConnectErr; + } + return result; } @@ -1385,11 +1322,11 @@ - (void)lookup:(int)aStateIndex didSucceedWithAddress4:(NSData *)address4 addres /** * This method is called if the DNS lookup fails. * This method is executed on the socketQueue. - * + * * Since the DNS lookup executed synchronously on a global concurrent queue, * the original connection request may have already been cancelled or timed-out by the time this method is invoked. * The lookupIndex tells us whether the lookup is still valid or not. -**/ + **/ - (void)lookup:(int)aStateIndex didFail:(NSError *)error { LogTrace(); @@ -1489,8 +1426,6 @@ - (BOOL)connectWithAddress4:(NSData *)address4 address6:(NSData *)address6 error dispatch_queue_t globalConcurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_async(globalConcurrentQueue, ^{ -#pragma clang diagnostic push -#pragma clang diagnostic warning "-Wimplicit-retain-self" int result = connect(socketFD, (const struct sockaddr *)[address bytes], (socklen_t)[address length]); @@ -1513,8 +1448,6 @@ - (BOOL)connectWithAddress4:(NSData *)address4 address6:(NSData *)address6 error } }); } - -#pragma clang diagnostic pop }); LogVerbose(@"Connecting..."); @@ -1595,7 +1528,7 @@ - (void)didConnect:(int)aStateIndex { NSString *host = [self connectedHost]; uint16_t port = [self connectedPort]; - __strong id theDelegate = delegate; + __strong id theDelegate = delegate; if (delegateQueue && [theDelegate respondsToSelector:@selector(socket:didConnectToHost:port:)]) { SetupStreamsPart1(); @@ -1665,31 +1598,15 @@ - (void)startConnectTimeout:(NSTimeInterval)timeout { dispatch_source_set_event_handler(connectTimer, ^{ @autoreleasepool { -#pragma clang diagnostic push -#pragma clang diagnostic warning "-Wimplicit-retain-self" __strong STCPSocket *strongSelf = weakSelf; - if (strongSelf == nil) + if (strongSelf == nil) { return_from_block; + } [strongSelf doConnectTimeout]; - -#pragma clang diagnostic pop } }); -#if !OS_OBJECT_USE_OBJC - dispatch_source_t theConnectTimer = connectTimer; - dispatch_source_set_cancel_handler(connectTimer, ^{ -#pragma clang diagnostic push -#pragma clang diagnostic warning "-Wimplicit-retain-self" - - LogVerbose(@"dispatch_release(connectTimer)"); - dispatch_release(theConnectTimer); - -#pragma clang diagnostic pop - }); -#endif - dispatch_time_t tt = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(timeout * NSEC_PER_SEC)); dispatch_source_set_timer(connectTimer, tt, DISPATCH_TIME_FOREVER, 0); @@ -1728,9 +1645,8 @@ - (void)doConnectTimeout { [self closeWithError:[self connectTimeoutError]]; } -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + #pragma mark Disconnecting -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - (void)closeWithError:(NSError *)error { LogTrace(); @@ -1770,7 +1686,7 @@ - (void)closeWithError:(NSError *)error { #endif [sslPreBuffer reset]; - sslErrCode = noErr; + sslErrCode = lastSSLHandshakeError = noErr; if (sslContext) { // Getting a linker error here about the SSLx() functions? @@ -1857,9 +1773,10 @@ - (void)closeWithError:(NSError *)error { // Clear stored socket info and all flags (config remains as is) socketFDBytesAvailable = 0; flags = 0; + sslWriteCachedLength = 0; if (shouldCallDelegate) { - __strong id theDelegate = delegate; + __strong id theDelegate = delegate; __strong id theSelf = isDeallocating ? nil : self; if (delegateQueue && [theDelegate respondsToSelector:@selector(socketDidDisconnect:withError:)]) { @@ -1926,7 +1843,7 @@ - (void)disconnectAfterReadingAndWriting { * Closes the socket if possible. * That is, if all writes have completed, and we're set to disconnect after writing, * or if all reads have completed, and we're set to disconnect after reading. -**/ + **/ - (void)maybeClose { NSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @"Must be dispatched on socketQueue"); @@ -2011,7 +1928,7 @@ - (NSError *)connectTimeoutError { /** * Returns a standard AsyncSocket maxed out error. -**/ + **/ - (NSError *)readMaxedOutError { NSString *errMsg = NSLocalizedStringWithDefaultValue(@"STCPSocketReadMaxedOutError", @"STCPSocket", @@ -2026,7 +1943,7 @@ - (NSError *)readMaxedOutError { /** * Returns a standard AsyncSocket write timeout error. -**/ + **/ - (NSError *)readTimeoutError { NSString *errMsg = NSLocalizedStringWithDefaultValue(@"STCPSocketReadTimeoutError", @"STCPSocket", @@ -2041,7 +1958,7 @@ - (NSError *)readTimeoutError { /** * Returns a standard AsyncSocket write timeout error. -**/ + **/ - (NSError *)writeTimeoutError { NSString *errMsg = NSLocalizedStringWithDefaultValue(@"STCPSocketWriteTimeoutError", @"STCPSocket", @@ -2449,12 +2366,12 @@ - (BOOL)isSecure { /** * Finds the address of an interface description. * An inteface description may be an interface name (en0, en1, lo0) or corresponding IP (192.168.4.34). - * + * * The interface description may optionally contain a port number at the end, separated by a colon. * If a non-zero port parameter is provided, any port number in the interface description is ignored. - * + * * The returned value is a 'struct sockaddr' wrapped in an NSMutableData object. -**/ + **/ - (void)getInterfaceAddress4:(NSMutableData **)interfaceAddr4Ptr address6:(NSMutableData **)interfaceAddr6Ptr fromDescription:(NSString *)interfaceDescription @@ -2605,8 +2522,6 @@ - (void)setupReadAndWriteSourcesForNewlyConnectedSocket:(int)socketFD { dispatch_source_set_event_handler(readSource, ^{ @autoreleasepool { -#pragma clang diagnostic push -#pragma clang diagnostic warning "-Wimplicit-retain-self" __strong STCPSocket *strongSelf = weakSelf; if (strongSelf == nil) return_from_block; @@ -2620,15 +2535,11 @@ - (void)setupReadAndWriteSourcesForNewlyConnectedSocket:(int)socketFD { [strongSelf doReadData]; else [strongSelf doReadEOF]; - -#pragma clang diagnostic pop } }); dispatch_source_set_event_handler(writeSource, ^{ @autoreleasepool { -#pragma clang diagnostic push -#pragma clang diagnostic warning "-Wimplicit-retain-self" __strong STCPSocket *strongSelf = weakSelf; if (strongSelf == nil) return_from_block; @@ -2637,56 +2548,28 @@ - (void)setupReadAndWriteSourcesForNewlyConnectedSocket:(int)socketFD { strongSelf->flags |= kSocketCanAcceptBytes; [strongSelf doWriteData]; - -#pragma clang diagnostic pop } }); // Setup cancel handlers __block int socketFDRefCount = 2; - -#if !OS_OBJECT_USE_OBJC - dispatch_source_t theReadSource = readSource; - dispatch_source_t theWriteSource = writeSource; -#endif - dispatch_source_set_cancel_handler(readSource, ^{ -#pragma clang diagnostic push -#pragma clang diagnostic warning "-Wimplicit-retain-self" - LogVerbose(@"readCancelBlock"); -#if !OS_OBJECT_USE_OBJC - LogVerbose(@"dispatch_release(readSource)"); - dispatch_release(theReadSource); -#endif - if (--socketFDRefCount == 0) { LogVerbose(@"close(socketFD)"); close(socketFD); } - -#pragma clang diagnostic pop }); dispatch_source_set_cancel_handler(writeSource, ^{ -#pragma clang diagnostic push -#pragma clang diagnostic warning "-Wimplicit-retain-self" - LogVerbose(@"writeCancelBlock"); -#if !OS_OBJECT_USE_OBJC - LogVerbose(@"dispatch_release(writeSource)"); - dispatch_release(theWriteSource); -#endif - if (--socketFDRefCount == 0) { LogVerbose(@"close(socketFD)"); close(socketFD); } - -#pragma clang diagnostic pop }); // We will not be able to read until data arrives. @@ -2963,14 +2846,14 @@ - (float)progressOfReadReturningTag:(long *)tagPtr bytesDone:(NSUInteger *)doneP /** * This method starts a new read, if needed. - * + * * It is called when: * - a user requests a read * - after a read request has finished (to handle the next request) * - immediately after the socket opens to handle any pending requests - * + * * This method also handles auto-disconnect post read/write completion. -**/ + **/ - (void)maybeDequeueRead { LogTrace(); NSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @"Must be dispatched on socketQueue"); @@ -3252,7 +3135,7 @@ - (void)doReadData { // The readQueue is waiting for SSL/TLS handshake to complete. if (flags & kStartingWriteTLS) { - if ([self usingSecureTransportForTLS]) { + if ([self usingSecureTransportForTLS] && lastSSLHandshakeError == errSSLWouldBlock) { // We are in the process of a SSL Handshake. // We were waiting for incoming data which has just arrived. @@ -3740,7 +3623,7 @@ - (void)doReadData { } else if (totalBytesReadForCurrentRead > 0) { // We're not done read type #2 or #3 yet, but we have read in some bytes - __strong id theDelegate = delegate; + __strong id theDelegate = delegate; if (delegateQueue && [theDelegate respondsToSelector:@selector(socket:didReadPartialDataOfLength:tag:)]) { long theReadTag = currentRead->tag; @@ -3837,7 +3720,7 @@ - (void)doReadEOF { // Notify the delegate that we're going half-duplex - __strong id theDelegate = delegate; + __strong id theDelegate = delegate; if (delegateQueue && [theDelegate respondsToSelector:@selector(socketDidCloseReadStream:)]) { dispatch_async(delegateQueue, ^{ @@ -3909,7 +3792,7 @@ - (void)completeCurrentRead { result = [NSData dataWithBytesNoCopy:buffer length:currentRead->bytesDone freeWhenDone:NO]; } - __strong id theDelegate = delegate; + __strong id theDelegate = delegate; if (delegateQueue && [theDelegate respondsToSelector:@selector(socket:didReadData:withTag:)]) { STCPReadPacket *theRead = currentRead; // Ensure currentRead retained since result may not own buffer @@ -3941,31 +3824,14 @@ - (void)setupReadTimerWithTimeout:(NSTimeInterval)timeout { dispatch_source_set_event_handler(readTimer, ^{ @autoreleasepool { -#pragma clang diagnostic push -#pragma clang diagnostic warning "-Wimplicit-retain-self" __strong STCPSocket *strongSelf = weakSelf; if (strongSelf == nil) return_from_block; [strongSelf doReadTimeout]; - -#pragma clang diagnostic pop } }); -#if !OS_OBJECT_USE_OBJC - dispatch_source_t theReadTimer = readTimer; - dispatch_source_set_cancel_handler(readTimer, ^{ -#pragma clang diagnostic push -#pragma clang diagnostic warning "-Wimplicit-retain-self" - - LogVerbose(@"dispatch_release(readTimer)"); - dispatch_release(theReadTimer); - -#pragma clang diagnostic pop - }); -#endif - dispatch_time_t tt = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(timeout * NSEC_PER_SEC)); dispatch_source_set_timer(readTimer, tt, DISPATCH_TIME_FOREVER, 0); @@ -3981,7 +3847,7 @@ - (void)doReadTimeout { flags |= kReadsPaused; - __strong id theDelegate = delegate; + __strong id theDelegate = delegate; if (delegateQueue && [theDelegate respondsToSelector:@selector(socket:shouldTimeoutReadWithTag:elapsed:bytesDone:)]) { STCPReadPacket *theRead = currentRead; @@ -4093,14 +3959,14 @@ - (float)progressOfWriteReturningTag:(long *)tagPtr bytesDone:(NSUInteger *)done /** * Conditionally starts a new write. - * + * * It is called when: * - a user requests a write * - after a write request has finished (to handle the next request) * - immediately after the socket opens to handle any pending requests - * + * * This method also handles auto-disconnect post read/write completion. -**/ + **/ - (void)maybeDequeueWrite { LogTrace(); NSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @"Must be dispatched on socketQueue"); @@ -4187,7 +4053,7 @@ - (void)doWriteData { // The writeQueue is waiting for SSL/TLS handshake to complete. if (flags & kStartingReadTLS) { - if ([self usingSecureTransportForTLS]) { + if ([self usingSecureTransportForTLS] && lastSSLHandshakeError == errSSLWouldBlock) { // We are in the process of a SSL Handshake. // We were waiting for available space in the socket's internal OS buffer to continue writing. @@ -4447,7 +4313,7 @@ - (void)doWriteData { if (bytesWritten > 0) { // We're not done with the entire write, but we have written some bytes - __strong id theDelegate = delegate; + __strong id theDelegate = delegate; if (delegateQueue && [theDelegate respondsToSelector:@selector(socket:didWritePartialDataOfLength:tag:)]) { long theWriteTag = currentWrite->tag; @@ -4462,7 +4328,6 @@ - (void)doWriteData { } // Check for errors - if (error) { [self closeWithError:[self errnoErrorWithReason:@"Error in write() function"]]; } @@ -4475,8 +4340,7 @@ - (void)completeCurrentWrite { NSAssert(currentWrite, @"Trying to complete current write when there is no current write."); - - __strong id theDelegate = delegate; + __strong id theDelegate = delegate; if (delegateQueue && [theDelegate respondsToSelector:@selector(socket:didWriteDataWithTag:)]) { long theWriteTag = currentWrite->tag; @@ -4508,31 +4372,14 @@ - (void)setupWriteTimerWithTimeout:(NSTimeInterval)timeout { dispatch_source_set_event_handler(writeTimer, ^{ @autoreleasepool { -#pragma clang diagnostic push -#pragma clang diagnostic warning "-Wimplicit-retain-self" __strong STCPSocket *strongSelf = weakSelf; if (strongSelf == nil) return_from_block; [strongSelf doWriteTimeout]; - -#pragma clang diagnostic pop } }); -#if !OS_OBJECT_USE_OBJC - dispatch_source_t theWriteTimer = writeTimer; - dispatch_source_set_cancel_handler(writeTimer, ^{ -#pragma clang diagnostic push -#pragma clang diagnostic warning "-Wimplicit-retain-self" - - LogVerbose(@"dispatch_release(writeTimer)"); - dispatch_release(theWriteTimer); - -#pragma clang diagnostic pop - }); -#endif - dispatch_time_t tt = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(timeout * NSEC_PER_SEC)); dispatch_source_set_timer(writeTimer, tt, DISPATCH_TIME_FOREVER, 0); @@ -4548,7 +4395,7 @@ - (void)doWriteTimeout { flags |= kWritesPaused; - __strong id theDelegate = delegate; + __strong id theDelegate = delegate; if (delegateQueue && [theDelegate respondsToSelector:@selector(socket:shouldTimeoutWriteWithTag:elapsed:bytesDone:)]) { STCPWritePacket *theWrite = currentWrite; @@ -5253,7 +5100,7 @@ - (void)ssl_startTLS { [sslPreBuffer didWrite:preBufferLength]; } - sslErrCode = noErr; + sslErrCode = lastSSLHandshakeError = noErr; // Start the SSL Handshake process @@ -5271,6 +5118,7 @@ - (void)ssl_continueSSLHandshake { // Otherwise, the return value indicates an error code. OSStatus status = SSLHandshake(sslContext); + lastSSLHandshakeError = status; if (status == noErr) { LogVerbose(@"SSLHandshake complete"); @@ -5280,7 +5128,7 @@ - (void)ssl_continueSSLHandshake { flags |= kSocketSecure; - __strong id theDelegate = delegate; + __strong id theDelegate = delegate; if (delegateQueue && [theDelegate respondsToSelector:@selector(socketDidSecure:)]) { dispatch_async(delegateQueue, ^{ @@ -5312,8 +5160,6 @@ - (void)ssl_continueSSLHandshake { void (^comletionHandler)(BOOL) = ^(BOOL shouldTrust) { @autoreleasepool { -#pragma clang diagnostic push -#pragma clang diagnostic warning "-Wimplicit-retain-self" dispatch_async(theSocketQueue, ^{ @autoreleasepool { if (trust) { @@ -5327,12 +5173,10 @@ - (void)ssl_continueSSLHandshake { } } }); - -#pragma clang diagnostic pop } }; - __strong id theDelegate = delegate; + __strong id theDelegate = delegate; if (delegateQueue && [theDelegate respondsToSelector:@selector(socket:didReceiveTrust:completionHandler:)]) { dispatch_async(delegateQueue, ^{ @@ -5381,6 +5225,7 @@ - (void)ssl_shouldTrustPeer:(BOOL)shouldTrust stateIndex:(int)aStateIndex { stateIndex++; if (shouldTrust) { + NSAssert(lastSSLHandshakeError == errSSLPeerAuthCompleted, @"ssl_shouldTrustPeer called when last error is %d and not errSSLPeerAuthCompleted", (int)lastSSLHandshakeError); [self ssl_continueSSLHandshake]; } else { [self closeWithError:[self sslError:errSSLPeerBadCert]]; @@ -5402,7 +5247,7 @@ - (void)cf_finishSSLHandshake { flags |= kSocketSecure; - __strong id theDelegate = delegate; + __strong id theDelegate = delegate; if (delegateQueue && [theDelegate respondsToSelector:@selector(socketDidSecure:)]) { dispatch_async(delegateQueue, ^{ @@ -5498,8 +5343,8 @@ - (void)cf_startTLS { // connection, and then a startTLS is issued. // So this mostly affects newer protocols (XMPP, IMAP) as opposed to older protocols (HTTPS). - if (!r1 && !r2) // Yes, the && is correct - workaround for apple bug. - { + // Yes, the && is correct - workaround for apple bug. + if (!r1 && !r2) { [self closeWithError:[self otherError:@"Error in CFStreamSetProperty"]]; return; } @@ -5905,7 +5750,7 @@ - (BOOL)openStreams { /** * See header file for big discussion of this method. -**/ + **/ - (BOOL)autoDisconnectOnClosedReadStream { // Note: YES means kAllowHalfDuplexConnection is OFF @@ -5924,7 +5769,7 @@ - (BOOL)autoDisconnectOnClosedReadStream { /** * See header file for big discussion of this method. -**/ + **/ - (void)setAutoDisconnectOnClosedReadStream:(BOOL)flag { // Note: YES means kAllowHalfDuplexConnection is OFF @@ -5945,7 +5790,7 @@ - (void)setAutoDisconnectOnClosedReadStream:(BOOL)flag { /** * See header file for big discussion of this method. -**/ + **/ - (void)markSocketQueueTargetQueue:(dispatch_queue_t)socketNewTargetQueue { void *nonNullUnusedPointer = (__bridge void *)self; dispatch_queue_set_specific(socketNewTargetQueue, IsOnSocketQueueOrTargetQueueKey, nonNullUnusedPointer, NULL); @@ -5953,14 +5798,14 @@ - (void)markSocketQueueTargetQueue:(dispatch_queue_t)socketNewTargetQueue { /** * See header file for big discussion of this method. -**/ + **/ - (void)unmarkSocketQueueTargetQueue:(dispatch_queue_t)socketOldTargetQueue { dispatch_queue_set_specific(socketOldTargetQueue, IsOnSocketQueueOrTargetQueueKey, NULL, NULL); } /** * See header file for big discussion of this method. -**/ + **/ - (void)performBlock:(dispatch_block_t)block { if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) block(); @@ -5970,7 +5815,7 @@ - (void)performBlock:(dispatch_block_t)block { /** * Questions? Have you read the header file? -**/ + **/ - (int)socketFD { if (!dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) { LogWarn(@"%@ - Method only available from within the context of a performBlock: invocation", THIS_METHOD); @@ -5985,7 +5830,7 @@ - (int)socketFD { /** * Questions? Have you read the header file? -**/ + **/ - (int)socket4FD { if (!dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) { LogWarn(@"%@ - Method only available from within the context of a performBlock: invocation", THIS_METHOD); @@ -5997,7 +5842,7 @@ - (int)socket4FD { /** * Questions? Have you read the header file? -**/ + **/ - (int)socket6FD { if (!dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) { LogWarn(@"%@ - Method only available from within the context of a performBlock: invocation", THIS_METHOD); @@ -6011,7 +5856,7 @@ - (int)socket6FD { /** * Questions? Have you read the header file? -**/ + **/ - (CFReadStreamRef)readStream { if (!dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) { LogWarn(@"%@ - Method only available from within the context of a performBlock: invocation", THIS_METHOD); @@ -6026,7 +5871,7 @@ - (CFReadStreamRef)readStream { /** * Questions? Have you read the header file? -**/ + **/ - (CFWriteStreamRef)writeStream { if (!dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) { LogWarn(@"%@ - Method only available from within the context of a performBlock: invocation", THIS_METHOD); @@ -6067,7 +5912,7 @@ - (BOOL)enableBackgroundingOnSocketWithCaveat:(BOOL)caveat { /** * Questions? Have you read the header file? -**/ + **/ - (BOOL)enableBackgroundingOnSocket { LogTrace(); diff --git a/SuperSocket/SuperSocket/STCPSocketDelegate.h b/SuperSocket/STCPSocketDelegate.h similarity index 97% rename from SuperSocket/SuperSocket/STCPSocketDelegate.h rename to SuperSocket/STCPSocketDelegate.h index 842a38d1..6d355cbb 100644 --- a/SuperSocket/SuperSocket/STCPSocketDelegate.h +++ b/SuperSocket/STCPSocketDelegate.h @@ -102,8 +102,8 @@ * Note that this method may be called multiple times for a single write if you return positive numbers. **/ - (NSTimeInterval)socket:(STCPSocket *)sock shouldTimeoutWriteWithTag:(long)tag - elapsed:(NSTimeInterval)elapsed - bytesDone:(NSUInteger)length; + elapsed:(NSTimeInterval)elapsed + bytesDone:(NSUInteger)length; /** * Conditionally called if the read stream closes, but the write stream may still be writeable. @@ -163,6 +163,6 @@ * It is safe to invoke the completionHandler block even if the socket has been closed. **/ - (void)socket:(STCPSocket *)sock didReceiveTrust:(SecTrustRef)trust -completionHandler:(void (^)(BOOL shouldTrustPeer))completionHandler; + completionHandler:(void (^)(BOOL shouldTrustPeer))completionHandler; @end diff --git a/SuperSocket/SuperSocket/STCPSocketPreBuffer.h b/SuperSocket/STCPSocketPreBuffer.h similarity index 99% rename from SuperSocket/SuperSocket/STCPSocketPreBuffer.h rename to SuperSocket/STCPSocketPreBuffer.h index e2f8cc26..35ec1102 100644 --- a/SuperSocket/SuperSocket/STCPSocketPreBuffer.h +++ b/SuperSocket/STCPSocketPreBuffer.h @@ -29,7 +29,7 @@ @interface STCPSocketPreBuffer : NSObject { uint8_t *preBuffer; size_t preBufferSize; - + uint8_t *readPointer; uint8_t *writePointer; } diff --git a/SuperSocket/SuperSocket/STCPSocketPreBuffer.m b/SuperSocket/STCPSocketPreBuffer.m similarity index 97% rename from SuperSocket/SuperSocket/STCPSocketPreBuffer.m rename to SuperSocket/STCPSocketPreBuffer.m index ec7b9bbf..42bfff19 100644 --- a/SuperSocket/SuperSocket/STCPSocketPreBuffer.m +++ b/SuperSocket/STCPSocketPreBuffer.m @@ -14,7 +14,7 @@ - (instancetype)initWithCapacity:(size_t)numBytes { if ((self = [super init])) { preBufferSize = numBytes; preBuffer = malloc(preBufferSize); - + readPointer = preBuffer; writePointer = preBuffer; } @@ -28,19 +28,19 @@ - (void)dealloc { - (void)ensureCapacityForWrite:(size_t)numBytes { size_t availableSpace = [self availableSpace]; - + 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; } @@ -63,7 +63,7 @@ - (void)getReadBuffer:(uint8_t **)bufferPtr availableBytes:(size_t *)availableBy - (void)didRead:(size_t)bytesRead { readPointer += bytesRead; - + if (readPointer == writePointer) { // The prebuffer has been drained. Reset pointers. readPointer = preBuffer; diff --git a/SuperSocket/STCPSpecialPacket.h b/SuperSocket/STCPSpecialPacket.h index a3416c62..4e0476af 100644 --- a/SuperSocket/STCPSpecialPacket.h +++ b/SuperSocket/STCPSpecialPacket.h @@ -13,7 +13,7 @@ * This class my be altered to support more than just TLS in the future. **/ @interface STCPSpecialPacket : NSObject { -@public + @public NSDictionary *tlsSettings; } - (instancetype)initWithTLSSettings:(NSDictionary *)settings; diff --git a/SuperSocket/SuperSocket/STCPWritePacket.h b/SuperSocket/STCPWritePacket.h similarity index 97% rename from SuperSocket/SuperSocket/STCPWritePacket.h rename to SuperSocket/STCPWritePacket.h index ce9332aa..6862f609 100644 --- a/SuperSocket/SuperSocket/STCPWritePacket.h +++ b/SuperSocket/STCPWritePacket.h @@ -12,7 +12,7 @@ * The GCDAsyncWritePacket encompasses the instructions for any given write. **/ @interface STCPWritePacket : NSObject { -@public + @public NSData *buffer; NSUInteger bytesDone; long tag; diff --git a/SuperSocket/SuperSocket/STCPWritePacket.m b/SuperSocket/STCPWritePacket.m similarity index 100% rename from SuperSocket/SuperSocket/STCPWritePacket.m rename to SuperSocket/STCPWritePacket.m diff --git a/SuperSocket/SuperSocket/SUDPSendPacket.h b/SuperSocket/SUDPSendPacket.h similarity index 96% rename from SuperSocket/SuperSocket/SUDPSendPacket.h rename to SuperSocket/SUDPSendPacket.h index a1c5c666..59fe3364 100644 --- a/SuperSocket/SuperSocket/SUDPSendPacket.h +++ b/SuperSocket/SUDPSendPacket.h @@ -12,17 +12,17 @@ * The GCDAsyncUdpSendPacket encompasses the instructions for a single send/write. **/ @interface SUDPSendPacket : NSObject { -@public + @public NSData *buffer; NSTimeInterval timeout; long tag; - + BOOL resolveInProgress; BOOL filterInProgress; - + NSArray *resolvedAddresses; NSError *resolveError; - + NSData *address; int addressFamily; } diff --git a/SuperSocket/SuperSocket/SUDPSendPacket.m b/SuperSocket/SUDPSendPacket.m similarity index 97% rename from SuperSocket/SuperSocket/SUDPSendPacket.m rename to SuperSocket/SUDPSendPacket.m index 36e72386..a18de8b5 100644 --- a/SuperSocket/SuperSocket/SUDPSendPacket.m +++ b/SuperSocket/SUDPSendPacket.m @@ -15,7 +15,7 @@ - (instancetype)initWithData:(NSData *)d timeout:(NSTimeInterval)t tag:(long)i { buffer = d; timeout = t; tag = i; - + resolveInProgress = NO; } return self; diff --git a/SuperSocket/SuperSocket/SUDPSocket.h b/SuperSocket/SUDPSocket.h similarity index 99% rename from SuperSocket/SuperSocket/SUDPSocket.h rename to SuperSocket/SUDPSocket.h index eb44d10b..91ffb74e 100644 --- a/SuperSocket/SuperSocket/SUDPSocket.h +++ b/SuperSocket/SUDPSocket.h @@ -423,6 +423,14 @@ typedef BOOL (^SUDPSocketSendFilterBlock)(NSData *data, NSData *address, long ta - (BOOL)leaveMulticastGroup:(NSString *)group error:(NSError **)errPtr; - (BOOL)leaveMulticastGroup:(NSString *)group onInterface:(NSString *)interface error:(NSError **)errPtr; +#pragma mark Reuse Port + +/** + * By default, only one socket can be bound to a given IP address + port at a time. + * To enable multiple processes to simultaneously bind to the same address+port, you need to enable this functionality in the socket. All processes that wish to use the address+port simultaneously must all enable reuse port on the socket bound to that port. + **/ +- (BOOL)enableReusePort:(BOOL)flag error:(NSError **)errPtr; + #pragma mark Broadcast /** diff --git a/SuperSocket/SuperSocket/SUDPSocket.m b/SuperSocket/SUDPSocket.m similarity index 96% rename from SuperSocket/SuperSocket/SUDPSocket.m rename to SuperSocket/SUDPSocket.m index 59d0238a..e09e3d10 100644 --- a/SuperSocket/SuperSocket/SUDPSocket.m +++ b/SuperSocket/SUDPSocket.m @@ -39,7 +39,7 @@ // Logging uses the CocoaLumberjack framework (which is also GCD based). // http://code.google.com/p/cocoalumberjack/ -// +// // It allows us to do a lot of logging without significantly slowing down the code. #import "DDLog.h" @@ -98,19 +98,19 @@ * Seeing a return statements within an inner block * can sometimes be mistaken for a return point of the enclosing method. * This makes inline blocks a bit easier to read. -**/ + **/ #define return_from_block return /** * A socket file descriptor is really just an integer. * It represents the index of the socket within the kernel. * This makes invalid file descriptor comparisons easier to read. -**/ -#define SOCKET_NULL -1 + **/ +NSInteger const SUDPSocketNull = -1; /** * Just to type less code. -**/ + **/ #define AutoreleasedBlock(block) ^{ \ @autoreleasepool { \ block(); \ @@ -298,16 +298,13 @@ - (instancetype)initWithDelegate:(id)aDelegate delegateQueue if (dq) { delegateQueue = dq; -#if !OS_OBJECT_USE_OBJC - dispatch_retain(delegateQueue); -#endif } max4ReceiveSize = 9216; max6ReceiveSize = 9216; - socket4FD = SOCKET_NULL; - socket6FD = SOCKET_NULL; + socket4FD = SUDPSocketNull; + socket6FD = SUDPSocketNull; if (sq) { NSAssert(sq != dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), @@ -318,9 +315,6 @@ - (instancetype)initWithDelegate:(id)aDelegate delegateQueue @"The given socketQueue parameter must not be a concurrent queue."); socketQueue = sq; -#if !OS_OBJECT_USE_OBJC - dispatch_retain(socketQueue); -#endif } else { socketQueue = dispatch_queue_create([SUDPSocketQueueName UTF8String], NULL); } @@ -376,16 +370,7 @@ - (void)dealloc { } delegate = nil; -#if !OS_OBJECT_USE_OBJC - if (delegateQueue) - dispatch_release(delegateQueue); -#endif delegateQueue = NULL; - -#if !OS_OBJECT_USE_OBJC - if (socketQueue) - dispatch_release(socketQueue); -#endif socketQueue = NULL; LogInfo(@"%@ - %@ (finish)", THIS_METHOD, self); @@ -449,24 +434,17 @@ - (dispatch_queue_t)delegateQueue { - (void)setDelegateQueue:(dispatch_queue_t)newDelegateQueue synchronously:(BOOL)synchronously { dispatch_block_t block = ^{ - -#if !OS_OBJECT_USE_OBJC - if (delegateQueue) - dispatch_release(delegateQueue); - if (newDelegateQueue) - dispatch_retain(newDelegateQueue); -#endif - delegateQueue = newDelegateQueue; }; if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) { block(); } else { - if (synchronously) + if (synchronously) { dispatch_sync(socketQueue, block); - else + } else { dispatch_async(socketQueue, block); + } } } @@ -502,26 +480,18 @@ - (void)getDelegate:(id *)delegatePtr delegateQueue:(dispatc - (void)setDelegate:(id)newDelegate delegateQueue:(dispatch_queue_t)newDelegateQueue synchronously:(BOOL)synchronously { dispatch_block_t block = ^{ - delegate = newDelegate; - -#if !OS_OBJECT_USE_OBJC - if (delegateQueue) - dispatch_release(delegateQueue); - if (newDelegateQueue) - dispatch_retain(newDelegateQueue); -#endif - delegateQueue = newDelegateQueue; }; if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) { block(); } else { - if (synchronously) + if (synchronously) { dispatch_sync(socketQueue, block); - else + } else { dispatch_async(socketQueue, block); + } } } @@ -800,7 +770,7 @@ - (void)notifyDidConnectToAddress:(NSData *)anAddress { LogTrace(); if (delegateQueue && [delegate respondsToSelector:@selector(udpSocket:didConnectToAddress:)]) { - id theDelegate = delegate; + id theDelegate = delegate; NSData *address = [anAddress copy]; // In case param is NSMutableData dispatch_async(delegateQueue, ^{ @@ -815,7 +785,7 @@ - (void)notifyDidNotConnect:(NSError *)error { LogTrace(); if (delegateQueue && [delegate respondsToSelector:@selector(udpSocket:didNotConnect:)]) { - id theDelegate = delegate; + id theDelegate = delegate; dispatch_async(delegateQueue, ^{ @autoreleasepool { @@ -829,7 +799,7 @@ - (void)notifyDidSendDataWithTag:(long)tag { LogTrace(); if (delegateQueue && [delegate respondsToSelector:@selector(udpSocket:didSendDataWithTag:)]) { - id theDelegate = delegate; + id theDelegate = delegate; dispatch_async(delegateQueue, ^{ @autoreleasepool { @@ -843,7 +813,7 @@ - (void)notifyDidNotSendDataWithTag:(long)tag dueToError:(NSError *)error { LogTrace(); if (delegateQueue && [delegate respondsToSelector:@selector(udpSocket:didNotSendDataWithTag:dueToError:)]) { - id theDelegate = delegate; + id theDelegate = delegate; dispatch_async(delegateQueue, ^{ @autoreleasepool { @@ -859,7 +829,7 @@ - (void)notifyDidReceiveData:(NSData *)data fromAddress:(NSData *)address withFi SEL selector = @selector(udpSocket:didReceiveData:fromAddress:withFilterContext:); if (delegateQueue && [delegate respondsToSelector:selector]) { - id theDelegate = delegate; + id theDelegate = delegate; dispatch_async(delegateQueue, ^{ @autoreleasepool { @@ -873,7 +843,7 @@ - (void)notifyDidCloseWithError:(NSError *)error { LogTrace(); if (delegateQueue && [delegate respondsToSelector:@selector(udpSocketDidClose:withError:)]) { - id theDelegate = delegate; + id theDelegate = delegate; dispatch_async(delegateQueue, ^{ @autoreleasepool { @@ -928,7 +898,7 @@ - (NSError *)errnoError { /** * Returns a standard send timeout error. -**/ + **/ - (NSError *)sendTimeoutError { NSString *errMsg = NSLocalizedStringWithDefaultValue(@"SUDPSocketSendTimeoutError", @"SUDPSocket", @@ -963,15 +933,14 @@ - (NSError *)otherError:(NSString *)errMsg { userInfo:userInfo]; } -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + #pragma mark Utilities -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - (BOOL)preOp:(NSError **)errPtr { NSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @"Must be dispatched on socketQueue"); - if (delegate == nil) // Must have delegate set - { + // Must have delegate set + if (delegate == nil) { if (errPtr) { NSString *msg = @"Attempting to use socket without a delegate. Set a delegate first."; *errPtr = [self badConfigError:msg]; @@ -979,8 +948,8 @@ - (BOOL)preOp:(NSError **)errPtr { return NO; } - if (delegateQueue == NULL) // Must have delegate queue set - { + // Must have delegate queue set + if (delegateQueue == NULL) { if (errPtr) { NSString *msg = @"Attempting to use socket without a delegate queue. Set a delegate queue first."; *errPtr = [self badConfigError:msg]; @@ -994,7 +963,7 @@ - (BOOL)preOp:(NSError **)errPtr { /** * This method executes on a global concurrent queue. * When complete, it executes the given completion block on the socketQueue. -**/ + **/ - (void)asyncResolveHost:(NSString *)aHost port:(uint16_t)port withCompletionBlock:(void (^)(NSArray *addresses, NSError *error))completionBlock { @@ -1097,10 +1066,10 @@ - (void)asyncResolveHost:(NSString *)aHost /** * This method picks an address from the given list of addresses. * The address picked depends upon which protocols are disabled, deactived, & preferred. - * + * * Returns the address family (AF_INET or AF_INET6) of the picked address, * or AF_UNSPEC and the corresponding error is there's a problem. -**/ + **/ - (int)getAddress:(NSData **)addressPtr error:(NSError **)errorPtr fromAddresses:(NSArray *)addresses { NSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @"Must be dispatched on socketQueue"); NSAssert([addresses count] > 0, @"Expected at least one address"); @@ -1243,7 +1212,7 @@ - (int)getAddress:(NSData **)addressPtr error:(NSError **)errorPtr fromAddresses /** * Finds the address(es) of an interface description. * An inteface description may be an interface name (en0, en1, lo0) or corresponding IP (192.168.4.34). -**/ + **/ - (void)convertIntefaceDescription:(NSString *)interfaceDescription port:(uint16_t)port intoAddress4:(NSData **)interfaceAddr4Ptr @@ -1375,7 +1344,7 @@ - (void)convertIntefaceDescription:(NSString *)interfaceDescription /** * Converts a numeric hostname into its corresponding address. * The hostname is expected to be an IPv4 or IPv6 address represented as a human-readable string. (e.g. 192.168.4.34) -**/ + **/ - (void)convertNumericHost:(NSString *)numericHost port:(uint16_t)port intoAddress4:(NSData **)addr4Ptr @@ -1584,20 +1553,9 @@ - (void)setupSendAndReceiveSourcesForSocket4 { int theSocketFD = socket4FD; -#if !OS_OBJECT_USE_OBJC - dispatch_source_t theSendSource = send4Source; - dispatch_source_t theReceiveSource = receive4Source; -#endif - dispatch_source_set_cancel_handler(send4Source, ^{ - LogVerbose(@"send4CancelBlock"); -#if !OS_OBJECT_USE_OBJC - LogVerbose(@"dispatch_release(send4Source)"); - dispatch_release(theSendSource); -#endif - if (--socketFDRefCount == 0) { LogVerbose(@"close(socket4FD)"); close(theSocketFD); @@ -1605,14 +1563,8 @@ - (void)setupSendAndReceiveSourcesForSocket4 { }); dispatch_source_set_cancel_handler(receive4Source, ^{ - LogVerbose(@"receive4CancelBlock"); -#if !OS_OBJECT_USE_OBJC - LogVerbose(@"dispatch_release(receive4Source)"); - dispatch_release(theReceiveSource); -#endif - if (--socketFDRefCount == 0) { LogVerbose(@"close(socket4FD)"); close(theSocketFD); @@ -1685,20 +1637,9 @@ - (void)setupSendAndReceiveSourcesForSocket6 { int theSocketFD = socket6FD; -#if !OS_OBJECT_USE_OBJC - dispatch_source_t theSendSource = send6Source; - dispatch_source_t theReceiveSource = receive6Source; -#endif - dispatch_source_set_cancel_handler(send6Source, ^{ - LogVerbose(@"send6CancelBlock"); -#if !OS_OBJECT_USE_OBJC - LogVerbose(@"dispatch_release(send6Source)"); - dispatch_release(theSendSource); -#endif - if (--socketFDRefCount == 0) { LogVerbose(@"close(socket6FD)"); close(theSocketFD); @@ -1706,14 +1647,8 @@ - (void)setupSendAndReceiveSourcesForSocket6 { }); dispatch_source_set_cancel_handler(receive6Source, ^{ - LogVerbose(@"receive6CancelBlock"); -#if !OS_OBJECT_USE_OBJC - LogVerbose(@"dispatch_release(receive6Source)"); - dispatch_release(theReceiveSource); -#endif - if (--socketFDRefCount == 0) { LogVerbose(@"close(socket6FD)"); close(theSocketFD); @@ -1745,11 +1680,11 @@ - (BOOL)createSocket4:(BOOL)useIPv4 socket6:(BOOL)useIPv6 error:(NSError **)errP int socketFD = socket(domain, SOCK_DGRAM, 0); - if (socketFD == SOCKET_NULL) { + if (socketFD == SUDPSocketNull) { if (errPtr) *errPtr = [self errnoErrorWithReason:@"Error in socket() function"]; - return SOCKET_NULL; + return SUDPSocketNull; } int status; @@ -1762,7 +1697,7 @@ - (BOOL)createSocket4:(BOOL)useIPv4 socket6:(BOOL)useIPv6 error:(NSError **)errP *errPtr = [self errnoErrorWithReason:@"Error enabling non-blocking IO on socket (fcntl)"]; close(socketFD); - return SOCKET_NULL; + return SUDPSocketNull; } int reuseaddr = 1; @@ -1772,7 +1707,7 @@ - (BOOL)createSocket4:(BOOL)useIPv4 socket6:(BOOL)useIPv6 error:(NSError **)errP *errPtr = [self errnoErrorWithReason:@"Error enabling address reuse (setsockopt)"]; close(socketFD); - return SOCKET_NULL; + return SUDPSocketNull; } int nosigpipe = 1; @@ -1782,7 +1717,7 @@ - (BOOL)createSocket4:(BOOL)useIPv4 socket6:(BOOL)useIPv6 error:(NSError **)errP *errPtr = [self errnoErrorWithReason:@"Error disabling sigpipe (setsockopt)"]; close(socketFD); - return SOCKET_NULL; + return SUDPSocketNull; } return socketFD; @@ -1794,7 +1729,7 @@ - (BOOL)createSocket4:(BOOL)useIPv4 socket6:(BOOL)useIPv6 error:(NSError **)errP LogVerbose(@"Creating IPv4 socket"); socket4FD = createSocket(AF_INET); - if (socket4FD == SOCKET_NULL) { + if (socket4FD == SUDPSocketNull) { // errPtr set in local createSocket() block return NO; } @@ -1804,12 +1739,12 @@ - (BOOL)createSocket4:(BOOL)useIPv4 socket6:(BOOL)useIPv6 error:(NSError **)errP LogVerbose(@"Creating IPv6 socket"); socket6FD = createSocket(AF_INET6); - if (socket6FD == SOCKET_NULL) { + if (socket6FD == SUDPSocketNull) { // errPtr set in local createSocket() block - if (socket4FD != SOCKET_NULL) { + if (socket4FD != SUDPSocketNull) { close(socket4FD); - socket4FD = SOCKET_NULL; + socket4FD = SUDPSocketNull; } return NO; @@ -1909,7 +1844,7 @@ - (void)resumeReceive6Source { } - (void)closeSocket4 { - if (socket4FD != SOCKET_NULL) { + if (socket4FD != SUDPSocketNull) { LogVerbose(@"dispatch_source_cancel(send4Source)"); dispatch_source_cancel(send4Source); @@ -1929,7 +1864,7 @@ - (void)closeSocket4 { send4Source = NULL; receive4Source = NULL; - socket4FD = SOCKET_NULL; + socket4FD = SUDPSocketNull; // Clear socket states @@ -1945,7 +1880,7 @@ - (void)closeSocket4 { } - (void)closeSocket6 { - if (socket6FD != SOCKET_NULL) { + if (socket6FD != SUDPSocketNull) { LogVerbose(@"dispatch_source_cancel(send6Source)"); dispatch_source_cancel(send6Source); @@ -1965,7 +1900,7 @@ - (void)closeSocket6 { // The sockets will be closed by the cancel handlers of the corresponding source - socket6FD = SOCKET_NULL; + socket6FD = SUDPSocketNull; // Clear socket states @@ -2037,7 +1972,7 @@ - (BOOL)getLocalAddress:(NSData **)dataPtr - (void)maybeUpdateCachedLocalAddress4Info { NSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @"Must be dispatched on socketQueue"); - if (cachedLocalAddress4 || ((flags & kDidBind) == 0) || (socket4FD == SOCKET_NULL)) { + if (cachedLocalAddress4 || ((flags & kDidBind) == 0) || (socket4FD == SUDPSocketNull)) { return; } @@ -2055,7 +1990,7 @@ - (void)maybeUpdateCachedLocalAddress4Info { - (void)maybeUpdateCachedLocalAddress6Info { NSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @"Must be dispatched on socketQueue"); - if (cachedLocalAddress6 || ((flags & kDidBind) == 0) || (socket6FD == SOCKET_NULL)) { + if (cachedLocalAddress6 || ((flags & kDidBind) == 0) || (socket6FD == SUDPSocketNull)) { return; } @@ -2075,7 +2010,7 @@ - (NSData *)localAddress { dispatch_block_t block = ^{ - if (socket4FD != SOCKET_NULL) { + if (socket4FD != SUDPSocketNull) { [self maybeUpdateCachedLocalAddress4Info]; result = cachedLocalAddress4; } else { @@ -2098,7 +2033,7 @@ - (NSString *)localHost { dispatch_block_t block = ^{ - if (socket4FD != SOCKET_NULL) { + if (socket4FD != SUDPSocketNull) { [self maybeUpdateCachedLocalAddress4Info]; result = cachedLocalHost4; } else { @@ -2120,7 +2055,7 @@ - (uint16_t)localPort { dispatch_block_t block = ^{ - if (socket4FD != SOCKET_NULL) { + if (socket4FD != SUDPSocketNull) { [self maybeUpdateCachedLocalAddress4Info]; result = cachedLocalPort4; } else { @@ -2251,7 +2186,7 @@ - (void)maybeUpdateCachedConnectedAddressInfo { uint16_t port = 0; int family = AF_UNSPEC; - if (socket4FD != SOCKET_NULL) { + if (socket4FD != SUDPSocketNull) { struct sockaddr_in sockaddr4; socklen_t sockaddr4len = sizeof(sockaddr4); @@ -2263,7 +2198,7 @@ - (void)maybeUpdateCachedConnectedAddressInfo { } else { LogWarn(@"Error in getpeername: %@", [self errnoError]); } - } else if (socket6FD != SOCKET_NULL) { + } else if (socket6FD != SUDPSocketNull) { struct sockaddr_in6 sockaddr6; socklen_t sockaddr6len = sizeof(sockaddr6); @@ -2372,7 +2307,7 @@ - (BOOL)isIPv4 { dispatch_block_t block = ^{ if (flags & kDidCreateSockets) { - result = (socket4FD != SOCKET_NULL); + result = (socket4FD != SUDPSocketNull); } else { result = [self isIPv4Enabled]; } @@ -2392,7 +2327,7 @@ - (BOOL)isIPv6 { dispatch_block_t block = ^{ if (flags & kDidCreateSockets) { - result = (socket6FD != SOCKET_NULL); + result = (socket6FD != SUDPSocketNull); } else { result = [self isIPv6Enabled]; } @@ -2413,7 +2348,7 @@ - (BOOL)isIPv6 { /** * This method runs through the various checks required prior to a bind attempt. * It is shared between the various bind methods. -**/ + **/ - (BOOL)preBind:(NSError **)errPtr { if (![self preOp:errPtr]) { return NO; @@ -2687,7 +2622,7 @@ - (BOOL)bindToAddress:(NSData *)localAddr error:(NSError **)errPtr { /** * This method runs through the various checks required prior to a connect attempt. * It is shared between the various connect methods. -**/ + **/ - (BOOL)preConnect:(NSError **)errPtr { if (![self preOp:errPtr]) { return NO; @@ -2755,8 +2690,8 @@ - (BOOL)connectToHost:(NSString *)host onPort:(uint16_t)port error:(NSError **)e LogVerbose(@"Dispatching DNS resolve for connect..."); [self asyncResolveHost:host - port:port - withCompletionBlock:^(NSArray *addresses, NSError *error) { + port:port + withCompletionBlock:^(NSArray *addresses, NSError *error) { // The asyncResolveHost:port:: method asynchronously dispatches a task onto the global concurrent queue, // and immediately returns. Once the async resolve task completes, @@ -2828,7 +2763,7 @@ - (BOOL)connectToAddress:(NSData *)remoteAddr error:(NSError **)errPtr { // So we copy it to be safe. NSData *address = [remoteAddr copy]; - NSArray *addresses = @[address]; + NSArray *addresses = @[ address ]; SUDPSpecialPacket *packet = [[SUDPSpecialPacket alloc] init]; packet->addresses = addresses; @@ -3042,7 +2977,7 @@ - (BOOL)performMulticastRequest:(int)requestType // Perform join - if ((socket4FD != SOCKET_NULL) && groupAddr4 && interfaceAddr4) { + if ((socket4FD != SUDPSocketNull) && groupAddr4 && interfaceAddr4) { const struct sockaddr_in *nativeGroup = (struct sockaddr_in *)[groupAddr4 bytes]; const struct sockaddr_in *nativeIface = (struct sockaddr_in *)[interfaceAddr4 bytes]; @@ -3061,7 +2996,7 @@ - (BOOL)performMulticastRequest:(int)requestType [self closeSocket6]; result = YES; - } else if ((socket6FD != SOCKET_NULL) && groupAddr6 && interfaceAddr6) { + } else if ((socket6FD != SUDPSocketNull) && groupAddr6 && interfaceAddr6) { const struct sockaddr_in6 *nativeGroup = (struct sockaddr_in6 *)[groupAddr6 bytes]; struct ipv6_mreq imreq; @@ -3099,9 +3034,64 @@ - (BOOL)performMulticastRequest:(int)requestType return result; } -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark Reuse Port + +- (BOOL)enableReusePort:(BOOL)flag error:(NSError *__autoreleasing *)errPtr { + __block BOOL result = NO; + __block NSError *err = nil; + + dispatch_block_t block = ^{ + @autoreleasepool { + if (![self preOp:&err]) { + return_from_block; + } + + if ((flags & kDidCreateSockets) == 0) { + if (![self createSockets:&err]) { + return_from_block; + } + } + + int value = flag ? 1 : 0; + if (socket4FD != SUDPSocketNull) { + int error = setsockopt(socket4FD, SOL_SOCKET, SO_REUSEPORT, (const void *)&value, sizeof(value)); + + if (error) { + err = [self errnoErrorWithReason:@"Error in setsockopt() function"]; + + return_from_block; + } + result = YES; + } + + if (socket6FD != SUDPSocketNull) { + int error = setsockopt(socket6FD, SOL_SOCKET, SO_REUSEPORT, (const void *)&value, sizeof(value)); + + if (error) { + err = [self errnoErrorWithReason:@"Error in setsockopt() function"]; + + return_from_block; + } + result = YES; + } + } + }; + + if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) { + block(); + } else { + dispatch_sync(socketQueue, block); + } + + if (errPtr) { + *errPtr = err; + } + + return result; +} + + #pragma mark Broadcast -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - (BOOL)enableBroadcast:(BOOL)flag error:(NSError **)errPtr { __block BOOL result = NO; @@ -3119,7 +3109,7 @@ - (BOOL)enableBroadcast:(BOOL)flag error:(NSError **)errPtr { } } - if (socket4FD != SOCKET_NULL) { + if (socket4FD != SUDPSocketNull) { int value = flag ? 1 : 0; int error = setsockopt(socket4FD, SOL_SOCKET, SO_BROADCAST, (const void *)&value, sizeof(value)); @@ -3189,8 +3179,8 @@ - (void)sendData:(NSData *)data packet->resolveInProgress = YES; [self asyncResolveHost:host - port:port - withCompletionBlock:^(NSArray *addresses, NSError *error) { + port:port + withCompletionBlock:^(NSArray *addresses, NSError *error) { // The asyncResolveHost:port:: method asynchronously dispatches a task onto the global concurrent queue, // and immediately returns. Once the async resolve task completes, @@ -3250,18 +3240,9 @@ - (void)setSendFilter:(SUDPSocketSendFilterBlock)filterBlock newFilterBlock = [filterBlock copy]; newFilterQueue = filterQueue; -#if !OS_OBJECT_USE_OBJC - dispatch_retain(newFilterQueue); -#endif } dispatch_block_t block = ^{ - -#if !OS_OBJECT_USE_OBJC - if (sendFilterQueue) - dispatch_release(sendFilterQueue); -#endif - sendFilterBlock = newFilterBlock; sendFilterQueue = newFilterQueue; sendFilterAsync = isAsynchronous; @@ -3323,9 +3304,9 @@ - (void)maybeDequeueSend { * This method is called after a sendPacket has been dequeued. * It performs various preprocessing checks on the packet, * and queries the sendFilter (if set) to determine if the packet can be sent. - * + * * If the packet passes all checks, it will be passed on to the doSend method. -**/ + **/ - (void)doPreSend { LogTrace(); @@ -3464,8 +3445,8 @@ - (void)doPreSend { /** * This method performs the actual sending of data in the currentSend packet. - * It should only be called if the -**/ + * It should only be called if the + **/ - (void)doSend { LogTrace(); @@ -3562,13 +3543,10 @@ - (void)doSend { /** * Releases all resources associated with the currentSend. -**/ + **/ - (void)endCurrentSend { if (sendTimer) { dispatch_source_cancel(sendTimer); -#if !OS_OBJECT_USE_OBJC - dispatch_release(sendTimer); -#endif sendTimer = NULL; } @@ -3577,7 +3555,7 @@ - (void)endCurrentSend { /** * Performs the operations to timeout the current send operation, and move on. -**/ + **/ - (void)doSendTimeout { LogTrace(); @@ -3589,7 +3567,7 @@ - (void)doSendTimeout { /** * Sets up a timer that fires to timeout the current send operation. * This method should only be called once per send packet. -**/ + **/ - (void)setupSendTimerWithTimeout:(NSTimeInterval)timeout { NSAssert(sendTimer == NULL, @"Invalid logic"); NSAssert(timeout >= 0.0, @"Invalid logic"); @@ -3739,27 +3717,19 @@ - (void)setReceiveFilter:(SUDPSocketReceiveFilterBlock)filterBlock newFilterBlock = [filterBlock copy]; newFilterQueue = filterQueue; -#if !OS_OBJECT_USE_OBJC - dispatch_retain(newFilterQueue); -#endif } dispatch_block_t block = ^{ - -#if !OS_OBJECT_USE_OBJC - if (receiveFilterQueue) - dispatch_release(receiveFilterQueue); -#endif - receiveFilterBlock = newFilterBlock; receiveFilterQueue = newFilterQueue; receiveFilterAsync = isAsynchronous; }; - if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) + if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) { block(); - else + } else { dispatch_async(socketQueue, block); + } } - (void)doReceive { @@ -3811,7 +3781,7 @@ - (void)doReceive { if (flags & kDidConnect) { // Connected socket - doReceive4 = (socket4FD != SOCKET_NULL); + doReceive4 = (socket4FD != SUDPSocketNull); } else { // Non-Connected socket @@ -3847,7 +3817,8 @@ - (void)doReceive { struct sockaddr_in sockaddr4; socklen_t sockaddr4len = sizeof(sockaddr4); - size_t bufSize = MIN(max4ReceiveSize, socket4FDBytesAvailable); + // HAX: Use maximum packet size since GCD doesn't necessarily return the whole size of a packet. + size_t bufSize = max4ReceiveSize; void *buf = malloc(bufSize); result = recvfrom(socket4FD, buf, bufSize, 0, (struct sockaddr *)&sockaddr4, &sockaddr4len); @@ -3877,7 +3848,8 @@ - (void)doReceive { struct sockaddr_in6 sockaddr6; socklen_t sockaddr6len = sizeof(sockaddr6); - size_t bufSize = MIN(max6ReceiveSize, socket6FDBytesAvailable); + // HAX: Use maximum packet size since GCD doesn't necessarily return an accurate packet size + size_t bufSize = max6ReceiveSize; void *buf = malloc(bufSize); result = recvfrom(socket6FD, buf, bufSize, 0, (struct sockaddr *)&sockaddr6, &sockaddr6len); @@ -4271,7 +4243,7 @@ - (BOOL)createReadAndWriteStreams:(NSError **)errPtr { return YES; } - if (socket4FD == SOCKET_NULL && socket6FD == SOCKET_NULL) { + if (socket4FD == SUDPSocketNull && socket6FD == SUDPSocketNull) { err = [self otherError:@"Cannot create streams without a file descriptor"]; goto Failed; } @@ -4280,7 +4252,7 @@ - (BOOL)createReadAndWriteStreams:(NSError **)errPtr { LogVerbose(@"Creating read and write stream(s)..."); - if (socket4FD != SOCKET_NULL) { + if (socket4FD != SUDPSocketNull) { CFStreamCreatePairWithSocket(NULL, (CFSocketNativeHandle)socket4FD, &readStream4, &writeStream4); if (!readStream4 || !writeStream4) { err = [self otherError:@"Error in CFStreamCreatePairWithSocket() [IPv4]"]; @@ -4288,7 +4260,7 @@ - (BOOL)createReadAndWriteStreams:(NSError **)errPtr { } } - if (socket6FD != SOCKET_NULL) { + if (socket6FD != SUDPSocketNull) { CFStreamCreatePairWithSocket(NULL, (CFSocketNativeHandle)socket6FD, &readStream6, &writeStream6); if (!readStream6 || !writeStream6) { err = [self otherError:@"Error in CFStreamCreatePairWithSocket() [IPv6]"]; @@ -4354,7 +4326,7 @@ - (BOOL)registerForStreamCallbacks:(NSError **)errPtr { // readStreamEvents |= (kCFStreamEventOpenCompleted | kCFStreamEventHasBytesAvailable); // writeStreamEvents |= (kCFStreamEventOpenCompleted | kCFStreamEventCanAcceptBytes); - if (socket4FD != SOCKET_NULL) { + if (socket4FD != SUDPSocketNull) { if (readStream4 == NULL || writeStream4 == NULL) { err = [self otherError:@"Read/Write stream4 is null"]; goto Failed; @@ -4369,7 +4341,7 @@ - (BOOL)registerForStreamCallbacks:(NSError **)errPtr { } } - if (socket6FD != SOCKET_NULL) { + if (socket6FD != SUDPSocketNull) { if (readStream6 == NULL || writeStream6 == NULL) { err = [self otherError:@"Read/Write stream6 is null"]; goto Failed; @@ -4432,7 +4404,7 @@ - (BOOL)openStreams:(NSError **)errPtr { NSError *err = nil; - if (socket4FD != SOCKET_NULL) { + if (socket4FD != SUDPSocketNull) { BOOL r1 = CFReadStreamOpen(readStream4); BOOL r2 = CFWriteStreamOpen(writeStream4); @@ -4442,7 +4414,7 @@ - (BOOL)openStreams:(NSError **)errPtr { } } - if (socket6FD != SOCKET_NULL) { + if (socket6FD != SUDPSocketNull) { BOOL r1 = CFReadStreamOpen(readStream6); BOOL r2 = CFWriteStreamOpen(writeStream6); @@ -4555,10 +4527,10 @@ - (int)socketFD { LogWarn(@"%@: %@ - Method only available from within the context of a performBlock: invocation", THIS_FILE, THIS_METHOD); - return SOCKET_NULL; + return SUDPSocketNull; } - if (socket4FD != SOCKET_NULL) + if (socket4FD != SUDPSocketNull) return socket4FD; else return socket6FD; @@ -4569,7 +4541,7 @@ - (int)socket4FD { LogWarn(@"%@: %@ - Method only available from within the context of a performBlock: invocation", THIS_FILE, THIS_METHOD); - return SOCKET_NULL; + return SUDPSocketNull; } return socket4FD; @@ -4580,7 +4552,7 @@ - (int)socket6FD { LogWarn(@"%@: %@ - Method only available from within the context of a performBlock: invocation", THIS_FILE, THIS_METHOD); - return SOCKET_NULL; + return SUDPSocketNull; } return socket6FD; diff --git a/SuperSocket/SuperSocket/SUDPSocketDelegate.h b/SuperSocket/SUDPSocketDelegate.h similarity index 97% rename from SuperSocket/SuperSocket/SUDPSocketDelegate.h rename to SuperSocket/SUDPSocketDelegate.h index 860893e7..4a75b808 100644 --- a/SuperSocket/SuperSocket/SUDPSocketDelegate.h +++ b/SuperSocket/SUDPSocketDelegate.h @@ -49,7 +49,7 @@ **/ - (void)udpSocket:(SUDPSocket *)sock didReceiveData:(NSData *)data fromAddress:(NSData *)address -withFilterContext:(id)filterContext; + withFilterContext:(id)filterContext; /** * Called when the socket is closed. diff --git a/SuperSocket/SuperSocket/SUDPSpecialPacket.h b/SuperSocket/SUDPSpecialPacket.h similarity index 95% rename from SuperSocket/SuperSocket/SUDPSpecialPacket.h rename to SuperSocket/SUDPSpecialPacket.h index 4fa650df..825bde1b 100644 --- a/SuperSocket/SuperSocket/SUDPSpecialPacket.h +++ b/SuperSocket/SUDPSpecialPacket.h @@ -9,11 +9,11 @@ #import @interface SUDPSpecialPacket : NSObject { -@public + @public // uint8_t type; - + BOOL resolveInProgress; - + NSArray *addresses; NSError *error; } diff --git a/SuperSocket/SuperSocket/SUDPSpecialPacket.m b/SuperSocket/SUDPSpecialPacket.m similarity index 100% rename from SuperSocket/SuperSocket/SUDPSpecialPacket.m rename to SuperSocket/SUDPSpecialPacket.m diff --git a/SuperSocket/SuperSocket/SuperSocket.h b/SuperSocket/SuperSocket.h similarity index 100% rename from SuperSocket/SuperSocket/SuperSocket.h rename to SuperSocket/SuperSocket.h diff --git a/SuperSocket/SuperSocketTests/Info.plist b/SuperSocketTests/Info.plist similarity index 100% rename from SuperSocket/SuperSocketTests/Info.plist rename to SuperSocketTests/Info.plist diff --git a/SuperSocket/SuperSocketTests/SuperSocketTests.m b/SuperSocketTests/SuperSocketTests.m similarity index 100% rename from SuperSocket/SuperSocketTests/SuperSocketTests.m rename to SuperSocketTests/SuperSocketTests.m diff --git a/supersocket.podspec b/supersocket.podspec new file mode 100644 index 00000000..3e13ef28 --- /dev/null +++ b/supersocket.podspec @@ -0,0 +1,10 @@ +Pod::Spec.new do |spec| + spec.name = 'SuperSocket' + spec.version = '8.1.0' + spec.license = { :type => 'Public Domain', :file => 'LICENSE' } + spec.homepage = 'https://github.com/livio/supersocket' + spec.authors = { 'Joel Fischer' => 'joel@livio.io' } + spec.summary = 'Asynchronous socket networking library forked from CocoaAsyncSocket' + spec.source = { :git => 'https://github.com/livio/supersocket.git', :tag => spec.version.to_s } + spec.source_files = 'SuperSocket/*.{h,m}' +end \ No newline at end of file