Skip to content

Commit 076eb7a

Browse files
committed
Bug fixes for problems introduced with last commit.
1 parent 26045b1 commit 076eb7a

File tree

2 files changed

+102
-56
lines changed

2 files changed

+102
-56
lines changed

GCD/GCDAsyncSocket.m

Lines changed: 95 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -4641,12 +4641,10 @@ - (void)doWriteData
46414641

46424642
// Note: This method is not called if theCurrentWrite is an GCDAsyncSpecialPacket (startTLS packet)
46434643

4644-
BOOL waiting = NO;
4644+
BOOL waiting = NO;
46454645
NSError *error = nil;
4646-
46474646
size_t bytesWritten = 0;
46484647

4649-
46504648
if (flags & kSocketSecure)
46514649
{
46524650
#if TARGET_OS_IPHONE
@@ -4661,7 +4659,6 @@ - (void)doWriteData
46614659
}
46624660

46634661
CFIndex result = CFWriteStreamWrite(writeStream, (UInt8 *)buffer, (CFIndex)bytesToWrite);
4664-
46654662
LogVerbose(@"CFWriteStreamWrite(%lu) = %li", bytesToWrite, result);
46664663

46674664
if (result < 0)
@@ -4670,12 +4667,14 @@ - (void)doWriteData
46704667
}
46714668
else
46724669
{
4673-
waiting = YES;
46744670
bytesWritten = (size_t)result;
4671+
4672+
// We always set waiting to true in this scenario.
4673+
// CFStream may have altered our underlying socket to non-blocking.
4674+
// Thus if we attempt to write without a callback, we may end up blocking our queue.
4675+
waiting = YES;
46754676
}
46764677

4677-
flags &= ~kSocketCanAcceptBytes;
4678-
46794678
#else
46804679

46814680
// We're going to use the SSLWrite function.
@@ -4721,7 +4720,10 @@ - (void)doWriteData
47214720

47224721
OSStatus result;
47234722

4724-
if (sslWriteCachedLength > 0)
4723+
BOOL hasCachedDataToWrite = (sslWriteCachedLength > 0);
4724+
BOOL hasNewDataToWrite = YES;
4725+
4726+
if (hasCachedDataToWrite)
47254727
{
47264728
size_t processed = 0;
47274729

@@ -4731,17 +4733,34 @@ - (void)doWriteData
47314733
{
47324734
bytesWritten = sslWriteCachedLength;
47334735
sslWriteCachedLength = 0;
4736+
4737+
if (currentWrite->bytesDone == [currentWrite->buffer length])
4738+
{
4739+
// We've written all data for the current write.
4740+
hasNewDataToWrite = NO;
4741+
}
47344742
}
47354743
else
47364744
{
4737-
// Handled "below"
4745+
if (result == errSSLWouldBlock)
4746+
{
4747+
waiting = YES;
4748+
}
4749+
else
4750+
{
4751+
error = [self sslError:result];
4752+
}
4753+
4754+
// Can't write any new data since we were unable to write the cached data.
4755+
hasNewDataToWrite = NO;
47384756
}
47394757
}
4740-
else
4758+
4759+
if (hasNewDataToWrite)
47414760
{
4742-
void *buffer = (void *)[currentWrite->buffer bytes] + currentWrite->bytesDone;
4761+
void *buffer = (void *)[currentWrite->buffer bytes] + currentWrite->bytesDone + bytesWritten;
47434762

4744-
NSUInteger bytesToWrite = [currentWrite->buffer length] - currentWrite->bytesDone;
4763+
NSUInteger bytesToWrite = [currentWrite->buffer length] - currentWrite->bytesDone - bytesWritten;
47454764

47464765
if (bytesToWrite > SIZE_MAX) // NSUInteger may be bigger than size_t (write param 3)
47474766
{
@@ -4770,28 +4789,20 @@ - (void)doWriteData
47704789
{
47714790
if (result == errSSLWouldBlock)
47724791
{
4792+
waiting = YES;
47734793
sslWriteCachedLength = sslBytesToWrite;
47744794
}
4795+
else
4796+
{
4797+
error = [self sslError:result];
4798+
}
47754799

47764800
keepLooping = NO;
4777-
4778-
// Additional handling "below"
47794801
}
4780-
}
4781-
}
4782-
4783-
if (result != noErr) // "Below"
4784-
{
4785-
if (result == errSSLWouldBlock)
4786-
{
4787-
waiting = YES;
4788-
flags &= ~kSocketCanAcceptBytes;
4789-
}
4790-
else
4791-
{
4792-
error = [self sslError:result];
4793-
}
4794-
}
4802+
4803+
} // while (keepLooping)
4804+
4805+
} // if (hasNewDataToWrite)
47954806

47964807
#endif
47974808
}
@@ -4815,30 +4826,47 @@ - (void)doWriteData
48154826
if (result < 0)
48164827
{
48174828
if (errno == EWOULDBLOCK)
4829+
{
48184830
waiting = YES;
4831+
}
48194832
else
4833+
{
48204834
error = [self errnoErrorWithReason:@"Error in write() function"];
4821-
4822-
flags &= ~kSocketCanAcceptBytes;
4823-
}
4824-
else if (result == 0)
4825-
{
4826-
waiting = YES;
4827-
flags &= ~kSocketCanAcceptBytes;
4835+
}
48284836
}
48294837
else
48304838
{
48314839
bytesWritten = result;
48324840
}
48334841
}
48344842

4843+
// We're done with our writing.
4844+
// If we explictly ran into a situation where the socket told us there was no room in the buffer,
4845+
// then we immediately resume listening for notifications.
4846+
//
4847+
// We must do this before we dequeue another write,
4848+
// as that may in turn invoke this method again.
4849+
//
4850+
// Note that if CFStream is involved, it may have maliciously put our socket in blocking mode.
4851+
4852+
if (waiting)
4853+
{
4854+
flags &= ~kSocketCanAcceptBytes;
4855+
4856+
if (![self usingCFStream])
4857+
{
4858+
[self resumeWriteSource];
4859+
}
4860+
}
4861+
4862+
// Check our results
4863+
48354864
BOOL done = NO;
48364865

48374866
if (bytesWritten > 0)
48384867
{
48394868
// Update total amount read for the current write
48404869
currentWrite->bytesDone += bytesWritten;
4841-
48424870
LogVerbose(@"currentWrite->bytesDone = %lu", currentWrite->bytesDone);
48434871

48444872
// Is packet done?
@@ -4854,22 +4882,40 @@ - (void)doWriteData
48544882
[self maybeDequeueWrite];
48554883
}
48564884
}
4857-
else if (bytesWritten > 0)
4885+
else
48584886
{
4859-
// We're not done with the entire write, but we have written some bytes
4887+
// We were unable to finish writing the data,
4888+
// so we're waiting for another callback to notify us of available space in the lower-level output buffer.
48604889

4861-
if (delegateQueue && [delegate respondsToSelector:@selector(socket:didWritePartialDataOfLength:tag:)])
4890+
if (!waiting & !error)
48624891
{
4863-
id theDelegate = delegate;
4864-
GCDAsyncWritePacket *theWrite = currentWrite;
4892+
// This would be the case if our write was able to accept some data, but not all of it.
48654893

4866-
dispatch_async(delegateQueue, ^{
4867-
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
4868-
4869-
[theDelegate socket:self didWritePartialDataOfLength:bytesWritten tag:theWrite->tag];
4894+
flags &= ~kSocketCanAcceptBytes;
4895+
4896+
if (![self usingCFStream])
4897+
{
4898+
[self resumeWriteSource];
4899+
}
4900+
}
4901+
4902+
if (bytesWritten > 0)
4903+
{
4904+
// We're not done with the entire write, but we have written some bytes
4905+
4906+
if (delegateQueue && [delegate respondsToSelector:@selector(socket:didWritePartialDataOfLength:tag:)])
4907+
{
4908+
id theDelegate = delegate;
4909+
GCDAsyncWritePacket *theWrite = currentWrite;
48704910

4871-
[pool drain];
4872-
});
4911+
dispatch_async(delegateQueue, ^{
4912+
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
4913+
4914+
[theDelegate socket:self didWritePartialDataOfLength:bytesWritten tag:theWrite->tag];
4915+
4916+
[pool drain];
4917+
});
4918+
}
48734919
}
48744920
}
48754921

@@ -4879,15 +4925,8 @@ - (void)doWriteData
48794925
{
48804926
[self closeWithError:[self errnoErrorWithReason:@"Error in write() function"]];
48814927
}
4882-
else if (waiting)
4883-
{
4884-
if (![self usingCFStream])
4885-
{
4886-
[self resumeWriteSource];
4887-
}
4888-
}
48894928

4890-
// Do not add any code here without first adding return statements in the error cases above.
4929+
// Do not add any code here without first adding a return statement in the error case above.
48914930
}
48924931

48934932
- (void)completeCurrentWrite

GCD/Xcode/IPhoneConnectTest/Classes/IPhoneConnectTestAppDelegate.m

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,13 +68,20 @@ - (void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(UI
6868

6969
if (port == 443)
7070
{
71+
72+
#if !TARGET_IPHONE_SIMULATOR
73+
74+
// Backgrounding doesn't seem to be supported on the simulator yet
75+
7176
[sock performBlock:^{
7277
if ([sock enableBackgroundingOnSocketWithCaveat])
7378
DDLogInfo(@"Enabled backgrounding on socket");
7479
else
7580
DDLogWarn(@"Enabling backgrounding failed!");
7681
}];
7782

83+
#endif
84+
7885
// Configure SSL/TLS settings
7986
NSMutableDictionary *settings = [NSMutableDictionary dictionaryWithCapacity:3];
8087

0 commit comments

Comments
 (0)