Navigation Menu

Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
robbiehanson committed Apr 15, 2011
2 parents 88c887d + 26f1c39 commit fe4d019
Show file tree
Hide file tree
Showing 2 changed files with 119 additions and 8 deletions.
31 changes: 31 additions & 0 deletions Vendor/CocoaAsyncSocket/GCDAsyncSocket.h
Expand Up @@ -84,6 +84,8 @@ typedef enum GCDAsyncSocketError GCDAsyncSocketError;
NSMutableData *sslReadBuffer;
size_t sslWriteCachedLength;
#endif

id userData;
}

/**
Expand Down Expand Up @@ -170,6 +172,13 @@ typedef enum GCDAsyncSocketError GCDAsyncSocketError;
- (BOOL)isIPv4PreferredOverIPv6;
- (void)setPreferIPv4OverIPv6:(BOOL)flag;

/**
* User data allows you to associate arbitrary information with the socket.
* This data is not used internally by socket in any way.
**/
- (id)userData;
- (void)setUserData:(id)arbitraryUserData;

#pragma mark Accepting

/**
Expand Down Expand Up @@ -224,6 +233,7 @@ typedef enum GCDAsyncSocketError GCDAsyncSocketError;
*
* The host may be a domain name (e.g. "deusty.com") or an IP address string (e.g. "192.168.0.2").
* The interface may be a name (e.g. "en1" or "lo0") or the corresponding IP address (e.g. "192.168.4.35").
* The interface may also be used to specify the local port (see below).
*
* To not time out use a negative time interval.
*
Expand All @@ -236,6 +246,16 @@ typedef enum GCDAsyncSocketError GCDAsyncSocketError;
* Since this class supports queued reads and writes, you can immediately start reading and/or writing.
* All read/write operations will be queued, and upon socket connection,
* the operations will be dequeued and processed in order.
*
* The interface may optionally contain a port number at the end of the string, separated by a colon.
* This allows you to specify the local port that should be used for the outgoing connection. (read paragraph to end)
* To specify both interface and local port: "en1:8082" or "192.168.4.35:2424".
* To specify only local port: ":8082".
* Please note this is an advanced feature, and is somewhat hidden on purpose.
* You should understand that 99.999% of the time you should NOT specify the local port for an outgoing connection.
* If you think you need to, there is a very good chance you have a fundamental misunderstanding somewhere.
* Local ports do NOT need to match remote ports. In fact, they almost never do.
* This feature is here for networking professionals using very advanced techniques.
**/
- (BOOL)connectToHost:(NSString *)host
onPort:(UInt16)port
Expand Down Expand Up @@ -272,6 +292,7 @@ typedef enum GCDAsyncSocketError GCDAsyncSocketError;
* struct sockaddr *sa -> NSData *dsa = [NSData dataWithBytes:remoteAddr length:remoteAddr->sa_len];
*
* The interface may be a name (e.g. "en1" or "lo0") or the corresponding IP address (e.g. "192.168.4.35").
* The interface may also be used to specify the local port (see below).
*
* The timeout is optional. To not time out use a negative time interval.
*
Expand All @@ -284,6 +305,16 @@ typedef enum GCDAsyncSocketError GCDAsyncSocketError;
* Since this class supports queued reads and writes, you can immediately start reading and/or writing.
* All read/write operations will be queued, and upon socket connection,
* the operations will be dequeued and processed in order.
*
* The interface may optionally contain a port number at the end of the string, separated by a colon.
* This allows you to specify the local port that should be used for the outgoing connection. (read paragraph to end)
* To specify both interface and local port: "en1:8082" or "192.168.4.35:2424".
* To specify only local port: ":8082".
* Please note this is an advanced feature, and is somewhat hidden on purpose.
* You should understand that 99.999% of the time you should NOT specify the local port for an outgoing connection.
* If you think you need to, there is a very good chance you have a fundamental misunderstanding somewhere.
* Local ports do NOT need to match remote ports. In fact, they almost never do.
* This feature is here for networking professionals using very advanced techniques.
**/
- (BOOL)connectToAddress:(NSData *)remoteAddr
viaInterface:(NSString *)interface
Expand Down
96 changes: 88 additions & 8 deletions Vendor/CocoaAsyncSocket/GCDAsyncSocket.m
Expand Up @@ -875,6 +875,8 @@ - (void)dealloc
[sslReadBuffer release];
#endif

[userData release];

LogInfo(@"%@ - %@ (finish)", THIS_METHOD, self);

[super dealloc];
Expand Down Expand Up @@ -1182,6 +1184,35 @@ - (void)setPreferIPv4OverIPv6:(BOOL)flag
}
}

- (id)userData
{
__block id result;

dispatch_block_t block = ^{

result = [userData retain];
};

if (dispatch_get_current_queue() == socketQueue)
block();
else
dispatch_sync(socketQueue, block);

return [result autorelease];
}

- (void)setUserData:(id)arbitraryUserData
{
dispatch_async(socketQueue, ^{

if (userData != arbitraryUserData)
{
[userData release];
userData = [arbitraryUserData retain];
}
});
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark Accepting
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -2152,6 +2183,15 @@ - (BOOL)connectWithAddress4:(NSData *)address4 address6:(NSData *)address6 error
{
LogVerbose(@"Binding socket...");

if ([[self class] portFromAddress:connectInterface] > 0)
{
// Since we're going to be binding to a specific port,
// we should turn on reuseaddr to allow us to override sockets in time_wait.

int reuseOn = 1;
setsockopt(socketFD, SOL_SOCKET, SO_REUSEADDR, &reuseOn, sizeof(reuseOn));
}

struct sockaddr *interfaceAddr = (struct sockaddr *)[connectInterface bytes];

int result = bind(socketFD, interfaceAddr, (socklen_t)[connectInterface length]);
Expand Down Expand Up @@ -3136,6 +3176,10 @@ - (BOOL)isIPv6
/**
* 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-zeor port parameter is provided, any port number in the interface description is ignored.
*
* The returned value is a 'struct sockaddr' wrapped in an NSData object.
**/
- (void)getInterfaceAddress4:(NSData **)interfaceAddr4Ptr
Expand All @@ -3146,7 +3190,28 @@ - (void)getInterfaceAddress4:(NSData **)interfaceAddr4Ptr
NSData *addr4 = nil;
NSData *addr6 = nil;

if (interfaceDescription == nil)
NSString *interface = nil;

NSArray *components = [interfaceDescription componentsSeparatedByString:@":"];
if ([components count] > 0)
{
NSString *temp = [components objectAtIndex:0];
if ([temp length] > 0)
{
interface = temp;
}
}
if ([components count] > 1 && port == 0)
{
long portL = strtol([[components objectAtIndex:1] UTF8String], NULL, 10);

if (portL > 0 && portL <= UINT16_MAX)
{
port = (UInt16)portL;
}
}

if (interface == nil)
{
// ANY address

Expand All @@ -3169,7 +3234,7 @@ - (void)getInterfaceAddress4:(NSData **)interfaceAddr4Ptr
addr4 = [NSData dataWithBytes:&nativeAddr4 length:sizeof(nativeAddr4)];
addr6 = [NSData dataWithBytes:&nativeAddr6 length:sizeof(nativeAddr6)];
}
else if ([interfaceDescription isEqualToString:@"localhost"] || [interfaceDescription isEqualToString:@"loopback"])
else if ([interface isEqualToString:@"localhost"] || [interface isEqualToString:@"loopback"])
{
// LOOPBACK address

Expand All @@ -3194,7 +3259,7 @@ - (void)getInterfaceAddress4:(NSData **)interfaceAddr4Ptr
}
else
{
const char *interface = [interfaceDescription UTF8String];
const char *iface = [interface UTF8String];

struct ifaddrs *addrs;
const struct ifaddrs *cursor;
Expand All @@ -3210,7 +3275,7 @@ - (void)getInterfaceAddress4:(NSData **)interfaceAddr4Ptr

struct sockaddr_in *addr = (struct sockaddr_in *)cursor->ifa_addr;

if (strcmp(cursor->ifa_name, interface) == 0)
if (strcmp(cursor->ifa_name, iface) == 0)
{
// Name match

Expand All @@ -3226,7 +3291,7 @@ - (void)getInterfaceAddress4:(NSData **)interfaceAddr4Ptr
const char *conversion;
conversion = inet_ntop(AF_INET, &addr->sin_addr, ip, sizeof(ip));

if ((conversion != NULL) && (strcmp(ip, interface) == 0))
if ((conversion != NULL) && (strcmp(ip, iface) == 0))
{
// IP match

Expand All @@ -3243,7 +3308,7 @@ - (void)getInterfaceAddress4:(NSData **)interfaceAddr4Ptr

struct sockaddr_in6 *addr = (struct sockaddr_in6 *)cursor->ifa_addr;

if (strcmp(cursor->ifa_name, interface) == 0)
if (strcmp(cursor->ifa_name, iface) == 0)
{
// Name match

Expand All @@ -3259,7 +3324,7 @@ - (void)getInterfaceAddress4:(NSData **)interfaceAddr4Ptr
const char *conversion;
conversion = inet_ntop(AF_INET6, &addr->sin6_addr, ip, sizeof(ip));

if ((conversion != NULL) && (strcmp(ip, interface) == 0))
if ((conversion != NULL) && (strcmp(ip, iface) == 0))
{
// IP match

Expand Down Expand Up @@ -3930,10 +3995,16 @@ - (void)doReadData
if (result < 0)
{
error = [NSMakeCollectable(CFReadStreamCopyError(readStream)) autorelease];

if (readIntoPartialReadBuffer)
[partialReadBuffer setLength:0];
}
else if (result == 0)
{
socketEOF = YES;

if (readIntoPartialReadBuffer)
[partialReadBuffer setLength:0];
}
else
{
Expand All @@ -3959,6 +4030,9 @@ - (void)doReadData
waiting = YES;
else
error = [self sslError:result];

if (readIntoPartialReadBuffer)
[partialReadBuffer setLength:0];
}

// Do not modify socketFDBytesAvailable.
Expand All @@ -3981,11 +4055,17 @@ - (void)doReadData
error = [self errnoErrorWithReason:@"Error in read() function"];

socketFDBytesAvailable = 0;

if (readIntoPartialReadBuffer)
[partialReadBuffer setLength:0];
}
else if (result == 0)
{
socketEOF = YES;
socketFDBytesAvailable = 0;

if (readIntoPartialReadBuffer)
[partialReadBuffer setLength:0];
}
else
{
Expand Down Expand Up @@ -5407,7 +5487,7 @@ - (void)maybeStartTLS
// 1. kCFStreamSSLPeerName

value = [tlsSettings objectForKey:(NSString *)kCFStreamSSLPeerName];
if (value)
if ([value isKindOfClass:[NSString class]])
{
NSString *peerName = (NSString *)value;

Expand Down

0 comments on commit fe4d019

Please sign in to comment.