diff --git a/Source/GCD/GCDAsyncSocket.m b/Source/GCD/GCDAsyncSocket.m index 866132d6..58c039a7 100644 --- a/Source/GCD/GCDAsyncSocket.m +++ b/Source/GCD/GCDAsyncSocket.m @@ -2619,6 +2619,8 @@ - (void)connectSocket:(int)socketFD address:(NSData *)address stateIndex:(int)aS if (result == 0) { + [self closeUnusedSocket:socketFD]; + [strongSelf didConnect:aStateIndex]; } else @@ -2640,7 +2642,8 @@ - (void)connectSocket:(int)socketFD address:(NSData *)address stateIndex:(int)aS LogVerbose(@"Connecting..."); } -- (void)closeSocket:(int)socketFD { +- (void)closeSocket:(int)socketFD +{ if (socketFD != SOCKET_NULL) { close(socketFD); @@ -2658,6 +2661,18 @@ - (void)closeSocket:(int)socketFD { } } +- (void)closeUnusedSocket:(int)usedSocketFD +{ + if (usedSocketFD != socket4FD) + { + [self closeSocket:socket4FD]; + } + else if (usedSocketFD != socket6FD) + { + [self closeSocket:socket6FD]; + } +} + - (BOOL)connectWithAddress4:(NSData *)address4 address6:(NSData *)address6 error:(NSError **)errPtr { LogTrace(); @@ -2716,7 +2731,7 @@ - (BOOL)connectWithAddress4:(NSData *)address4 address6:(NSData *)address6 error if (alternateAddress) { - NSTimeInterval alternateAddressDelay = 0.5; + NSTimeInterval alternateAddressDelay = 0.3; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(alternateAddressDelay * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ [self connectSocket:alternateSocketFD address:alternateAddress stateIndex:aStateIndex]; }); diff --git a/Tests/Shared/GCDAsyncSocketConnectionTests.m b/Tests/Shared/GCDAsyncSocketConnectionTests.m index 7717ac0b..f2655b24 100644 --- a/Tests/Shared/GCDAsyncSocketConnectionTests.m +++ b/Tests/Shared/GCDAsyncSocketConnectionTests.m @@ -56,6 +56,84 @@ - (void)testFullConnection { }]; } +- (void)testConnectionWithAnIPv4OnlyServer { + self.serverSocket.IPv6Enabled = NO; + + NSError *error = nil; + BOOL success = NO; + success = [self.serverSocket acceptOnPort:kTestPort error:&error]; + XCTAssertTrue(success, @"Server failed setting up socket on port %d %@", kTestPort, error); + success = [self.clientSocket connectToHost:@"127.0.0.1" onPort:kTestPort error:&error]; + XCTAssertTrue(success, @"Client failed connecting to up server socket on port %d %@", kTestPort, error); + + self.expectation = [self expectationWithDescription:@"Test Full Connection"]; + [self waitForExpectationsWithTimeout:30 handler:^(NSError *error) { + if (error) { + NSLog(@"Error establishing test connection"); + } + else { + XCTAssertTrue(self.acceptedServerSocket.isIPv4, @"Established connection is not IPv4"); + } + }]; +} + +- (void)testConnectionWithAnIPv6OnlyServer { + self.serverSocket.IPv4Enabled = NO; + + NSError *error = nil; + BOOL success = NO; + success = [self.serverSocket acceptOnPort:kTestPort error:&error]; + XCTAssertTrue(success, @"Server failed setting up socket on port %d %@", kTestPort, error); + success = [self.clientSocket connectToHost:@"::1" onPort:kTestPort error:&error]; + XCTAssertTrue(success, @"Client failed connecting to up server socket on port %d %@", kTestPort, error); + + self.expectation = [self expectationWithDescription:@"Test Full Connection"]; + [self waitForExpectationsWithTimeout:30 handler:^(NSError *error) { + if (error) { + NSLog(@"Error establishing test connection"); + } + else { + XCTAssertTrue(self.acceptedServerSocket.isIPv6, @"Established connection is not IPv6"); + } + }]; +} + +- (void)testConnectionWithLocalhostWithClientPreferringIPv4 { + [self.clientSocket setIPv4PreferredOverIPv6:YES]; + + NSError *error = nil; + BOOL success = NO; + success = [self.serverSocket acceptOnPort:kTestPort error:&error]; + XCTAssertTrue(success, @"Server failed setting up socket on port %d %@", kTestPort, error); + success = [self.clientSocket connectToHost:@"localhost" onPort:kTestPort error:&error]; + XCTAssertTrue(success, @"Client failed connecting to up server socket on port %d %@", kTestPort, error); + + self.expectation = [self expectationWithDescription:@"Test Full Connection"]; + [self waitForExpectationsWithTimeout:30 handler:^(NSError *error) { + if (error) { + NSLog(@"Error establishing test connection"); + } + }]; +} + +- (void)testConnectionWithLocalhostWithClientPreferringIPv6 { + [self.clientSocket setIPv4PreferredOverIPv6:NO]; + + NSError *error = nil; + BOOL success = NO; + success = [self.serverSocket acceptOnPort:kTestPort error:&error]; + XCTAssertTrue(success, @"Server failed setting up socket on port %d %@", kTestPort, error); + success = [self.clientSocket connectToHost:@"localhost" onPort:kTestPort error:&error]; + XCTAssertTrue(success, @"Client failed connecting to up server socket on port %d %@", kTestPort, error); + + self.expectation = [self expectationWithDescription:@"Test Full Connection"]; + [self waitForExpectationsWithTimeout:30 handler:^(NSError *error) { + if (error) { + NSLog(@"Error establishing test connection"); + } + }]; +} + #pragma mark GCDAsyncSocketDelegate methods /** diff --git a/Tests/Shared/SwiftTests.swift b/Tests/Shared/SwiftTests.swift index ebae2bbe..8065c87e 100644 --- a/Tests/Shared/SwiftTests.swift +++ b/Tests/Shared/SwiftTests.swift @@ -56,7 +56,98 @@ class SwiftTests: XCTestCase, GCDAsyncSocketDelegate { } } } + + func testConnectionWithAnIPv4OnlyServer() { + serverSocket?.IPv6Enabled = false + do { + try serverSocket?.acceptOnPort(kTestPort) + } catch { + XCTFail("\(error)") + } + do { + try clientSocket?.connectToHost("127.0.0.1", onPort: kTestPort) + } catch { + XCTFail("\(error)") + } + expectation = expectationWithDescription("Test Full connnection") + waitForExpectationsWithTimeout(30) { (error: NSError?) -> Void in + if error != nil { + XCTFail("\(error)") + } + else { + if let isIPv4 = self.acceptedServerSocket?.isIPv4 { + XCTAssertTrue(isIPv4) + } + } + } + } + func testConnectionWithAnIPv6OnlyServer() { + serverSocket?.IPv4Enabled = false + do { + try serverSocket?.acceptOnPort(kTestPort) + } catch { + XCTFail("\(error)") + } + do { + try clientSocket?.connectToHost("::1", onPort: kTestPort) + } catch { + XCTFail("\(error)") + } + expectation = expectationWithDescription("Test Full connnection") + waitForExpectationsWithTimeout(30) { (error: NSError?) -> Void in + if error != nil { + XCTFail("\(error)") + } + else { + if let isIPv6 = self.acceptedServerSocket?.isIPv6 { + XCTAssertTrue(isIPv6) + } + } + } + } + + func testConnectionWithLocalhostWithClientPreferringIPv4() { + clientSocket?.IPv4PreferredOverIPv6 = true + + do { + try serverSocket?.acceptOnPort(kTestPort) + } catch { + XCTFail("\(error)") + } + do { + try clientSocket?.connectToHost("localhost", onPort: kTestPort) + } catch { + XCTFail("\(error)") + } + expectation = expectationWithDescription("Test Full connnection") + waitForExpectationsWithTimeout(30) { (error: NSError?) -> Void in + if error != nil { + XCTFail("\(error)") + } + } + } + + func testConnectionWithLocalhostWithClientPreferringIPv6() { + clientSocket?.IPv4PreferredOverIPv6 = false + + do { + try serverSocket?.acceptOnPort(kTestPort) + } catch { + XCTFail("\(error)") + } + do { + try clientSocket?.connectToHost("localhost", onPort: kTestPort) + } catch { + XCTFail("\(error)") + } + expectation = expectationWithDescription("Test Full connnection") + waitForExpectationsWithTimeout(30) { (error: NSError?) -> Void in + if error != nil { + XCTFail("\(error)") + } + } + } //MARK:- GCDAsyncSocketDelegate func socket(sock: GCDAsyncSocket!, didAcceptNewSocket newSocket: GCDAsyncSocket!) {