Skip to content

Commit

Permalink
Merged bug fixes submitted by users, and from within Mojo.
Browse files Browse the repository at this point in the history
See changes.txt for details.
  • Loading branch information
robbiehanson committed May 2, 2008
1 parent f3e16df commit 9039143
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 62 deletions.
112 changes: 51 additions & 61 deletions AsyncSocket.m
Original file line number Diff line number Diff line change
Expand Up @@ -98,10 +98,6 @@ - (void) doCFCallback:(CFSocketCallBackType)type forSocket:(CFSocketRef)sock wit
- (void) doCFReadStreamCallback:(CFStreamEventType)type forStream:(CFReadStreamRef)stream;
- (void) doCFWriteStreamCallback:(CFStreamEventType)type forStream:(CFWriteStreamRef)stream;

// Utilities
- (NSData *) sockaddrFromString:(NSString *)addrStr port:(UInt16)port error:(NSError **)errPtr;


@end

static void MyCFSocketCallback (CFSocketRef, CFSocketCallBackType, CFDataRef, const void *, void *);
Expand Down Expand Up @@ -367,8 +363,47 @@ - (BOOL)acceptOnAddress:(NSString *)hostaddr port:(UInt16)port error:(NSError **
NSData *address = nil, *address6 = nil;
if(hostaddr && ([hostaddr length] != 0))
{
address = [self sockaddrFromString:hostaddr port:port error:errPtr];
if (!address) return NO;
NSString *portStr = [NSString stringWithFormat:@"%hu", port];

@synchronized (getaddrinfoLock)
{
struct addrinfo hints, *res, *res0;

memset(&hints, 0, sizeof(hints));
hints.ai_family = PF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
hints.ai_flags = AI_PASSIVE;

int error = getaddrinfo([hostaddr UTF8String], [portStr UTF8String], &hints, &res0);

if(error)
{
NSString *errMsg = [NSString stringWithCString:gai_strerror(error) encoding:NSASCIIStringEncoding];
NSDictionary *info = [NSDictionary dictionaryWithObject:errMsg forKey:NSLocalizedDescriptionKey];

*errPtr = [NSError errorWithDomain:@"kCFStreamErrorDomainNetDB" code:error userInfo:info];
}

for(res = res0; res; res = res->ai_next)
{
if(!address && (res->ai_family == AF_INET))
{
// Found IPv4 address
// Wrap the native address structures for CFSocketSetAddress.
address = [NSData dataWithBytes:res->ai_addr length:res->ai_addrlen];
}
else if(!address6 && (res->ai_family == AF_INET6))
{
// Found IPv6 address
// Wrap the native address structures for CFSocketSetAddress.
address6 = [NSData dataWithBytes:res->ai_addr length:res->ai_addrlen];
}
}
freeaddrinfo(res0);
}

if(!address && !address6) return NO;
}
else
{
Expand All @@ -389,8 +424,8 @@ - (BOOL)acceptOnAddress:(NSString *)hostaddr port:(UInt16)port error:(NSError **
nativeAddr6.sin6_scope_id = 0;

// Wrap the native address structures for CFSocketSetAddress.
address = [NSData dataWithBytesNoCopy:&nativeAddr length:sizeof(nativeAddr) freeWhenDone:NO];
address6 = [NSData dataWithBytesNoCopy:&nativeAddr6 length:sizeof(nativeAddr6) freeWhenDone:NO];
address = [NSData dataWithBytes:&nativeAddr length:sizeof(nativeAddr)];
address6 = [NSData dataWithBytes:&nativeAddr6 length:sizeof(nativeAddr6)];
}

// Create the sockets.
Expand Down Expand Up @@ -561,9 +596,9 @@ - (void)doAcceptWithSocket:(CFSocketNativeHandle)newNative
BOOL pass = YES;

if(pass && ![newSocket createStreamsFromNative:newNative error:nil]) pass = NO;
if(pass && ![newSocket attachStreamsToRunLoop:runLoop error:nil]) pass = NO;
if(pass && ![newSocket configureStreamsAndReturnError:nil]) pass = NO;
if(pass && ![newSocket openStreamsAndReturnError:nil]) pass = NO;
if(pass && ![newSocket attachStreamsToRunLoop:runLoop error:nil]) pass = NO;
if(pass && ![newSocket configureStreamsAndReturnError:nil]) pass = NO;
if(pass && ![newSocket openStreamsAndReturnError:nil]) pass = NO;

if(pass)
newSocket->theFlags |= kDidPassConnectMethod;
Expand Down Expand Up @@ -720,6 +755,7 @@ - (void)doStreamOpen
{
NSLog (@"AsyncSocket %p couldn't get socket from streams, %@. Disconnecting.", self, err);
[self closeWithError:err];
return;
}

// Call the delegate.
Expand Down Expand Up @@ -802,18 +838,20 @@ - (void) close
[self emptyQueues];
[partialReadBuffer release];
partialReadBuffer = nil;
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(disconnect) object:nil];

[NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(disconnect) object:nil];
// Close streams.
if (theReadStream != NULL)
{
CFReadStreamSetClient(theReadStream, kCFStreamEventNone, NULL, NULL);
CFReadStreamUnscheduleFromRunLoop (theReadStream, theRunLoop, kCFRunLoopDefaultMode);
CFReadStreamClose (theReadStream);
CFRelease (theReadStream);
theReadStream = NULL;
}
if (theWriteStream != NULL)
{
CFWriteStreamSetClient(theWriteStream, kCFStreamEventNone, NULL, NULL);
CFWriteStreamUnscheduleFromRunLoop (theWriteStream, theRunLoop, kCFRunLoopDefaultMode);
CFWriteStreamClose (theWriteStream);
CFRelease (theWriteStream);
Expand Down Expand Up @@ -1690,52 +1728,4 @@ static void MyCFWriteStreamCallback (CFWriteStreamRef stream, CFStreamEventType
[socket doCFWriteStreamCallback:type forStream:stream];
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark Utilities
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

- (NSData *) sockaddrFromString:(NSString *)addrStr port:(UInt16)port error:(NSError **)errPtr
{
NSData *resultData = nil;

struct addrinfo hints = {0}, *result;
hints.ai_family = PF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
hints.ai_flags = AI_NUMERICHOST | AI_PASSIVE;

@synchronized (getaddrinfoLock)
{
NSData *addrStrData = [addrStr dataUsingEncoding:NSASCIIStringEncoding
allowLossyConversion:YES];

char portStr[] = "65535"; // Reserve space for max port number.
snprintf(portStr, sizeof(portStr), "%u", port);

int err = getaddrinfo ([addrStrData bytes], portStr,
(const struct addrinfo *)&hints,
(struct addrinfo **)&result);
if (!err)
{
resultData = [NSData dataWithBytes:result->ai_addr
length:result->ai_addrlen];
freeaddrinfo (result);
}
else if (errPtr)
{
NSString *errMsg = [NSString stringWithCString: gai_strerror(err)
encoding: NSASCIIStringEncoding];

NSDictionary *info = [NSDictionary dictionaryWithObjectsAndKeys:
errMsg, NSLocalizedDescriptionKey, nil];

*errPtr = [NSError errorWithDomain:@"kCFStreamErrorDomainNetDB"
code:err
userInfo:info];
}
}

return resultData;
}

@end
28 changes: 27 additions & 1 deletion changes.txt
Original file line number Diff line number Diff line change
Expand Up @@ -61,4 +61,30 @@ Bugfix:
In doWriteTimeout: the code was calling completeCurrentWrite and then closes with an error.
This resulted in the delegate being told that his write completed (when it didn't)
immediately prior to disconnecting with an error.





CHANGES IN VERSION 4.3.5

Added support for accepting on IPv6 address.

Bugfix:
In acceptOnAddress, changed dataWithBytesNoCopy to dataWithBytes.
This was needed because the bytes were about to go out of scope.

Bugfix:
Added return statement to doStreamOpen after closewithError call.
This was needed or else the didConnect delegate could potentially get called
immediately after willCloseWithError and didClose.

Bugfix:
We were receiving several reports of crashes in AsyncSocket.
The problem seemed to be that, in specific circumstances,
the readStream callback and/or writeStream callback would be invoked AFTER
the readStream and writeStream were closed.
This isn't supposed to happen, however we did find evidence that it was an issue several years ago.
It was assumed that the problem has since been fixed.
Perhaps the problem still exists, but only in very rare cases which we just happened to be encountering.
In any case, we used the same precautions that were used previously.
In the close methods, we specifically unregister for callbacks now.

0 comments on commit 9039143

Please sign in to comment.