From d607cd7064e7ba41e2b6a2f06d9473421e3ef102 Mon Sep 17 00:00:00 2001 From: Kevin Wooten Date: Wed, 27 Sep 2017 13:08:26 -0700 Subject: [PATCH] Add support for IPv4 to TCPSocket --- Sources/DefaultHTTPServer.swift | 3 +- Sources/TCPSocket.swift | 202 +++++++++++++----- Tests/EmbassyTests/KqueueSelectorTests.swift | 26 +-- Tests/EmbassyTests/SelectSelectorTests.swift | 26 +-- .../EmbassyTests/SelectorEventLoopTests.swift | 12 +- Tests/EmbassyTests/TCPSocketTests.swift | 131 ++++++++++-- Tests/EmbassyTests/TransportTests.swift | 16 +- 7 files changed, 312 insertions(+), 104 deletions(-) diff --git a/Sources/DefaultHTTPServer.swift b/Sources/DefaultHTTPServer.swift index e649564..e0cbc9d 100644 --- a/Sources/DefaultHTTPServer.swift +++ b/Sources/DefaultHTTPServer.swift @@ -49,8 +49,7 @@ public final class DefaultHTTPServer: HTTPServer { return } logger.info("Starting HTTP server on [\(interface)]:\(port) ...") - acceptSocket = try TCPSocket() - try acceptSocket.bind(port: port, interface: interface) + acceptSocket = try TCPSocket(boundToPort: port, onInterface: interface) try acceptSocket.listen() eventLoop.setReader(acceptSocket.fileDescriptor) { [unowned self] in self.handleNewConnection() diff --git a/Sources/TCPSocket.swift b/Sources/TCPSocket.swift index bd1a8b3..75ff58b 100644 --- a/Sources/TCPSocket.swift +++ b/Sources/TCPSocket.swift @@ -8,9 +8,34 @@ import Foundation -/// Class wrapping around TCP/IPv6 socket + +public protocol TCPSocketAddress { + + static var family: TCPSocket.Family { get } + static var loopbackName: String { get } + + func asData() -> Data + + static func allocate() -> Data + static func from(address: String, port: UInt16) throws -> TCPSocketAddress + +} + +/// Class wrapping around TCP/IP socket public final class TCPSocket { + + public enum Error: Swift.Error { + case unknownFamily + } + + public enum Family: Int32 { + case v4 + case v6 + } + + /// The file descriptor number for socket + let family: Family let fileDescriptor: Int32 /// Whether is this socket in block mode or not @@ -61,20 +86,31 @@ public final class TCPSocket { } } - init(blocking: Bool = false) throws { + convenience init(boundToPort port: Int, onInterface interface: String, addressReusable: Bool = true) throws { + try self.init(familyOf: interface) + try bind(port: port, interface: interface, addressReusable: addressReusable) + } + + convenience init(familyOf address: String) throws { + try self.init(family: Family.from(address: address)) + } + + init(family: Family, blocking: Bool = false) throws { + self.family = family #if os(Linux) let socketType = Int32(SOCK_STREAM.rawValue) #else let socketType = SOCK_STREAM #endif - fileDescriptor = SystemLibrary.socket(AF_INET6, socketType, 0) + fileDescriptor = SystemLibrary.socket(family.constant, socketType, 0) guard fileDescriptor >= 0 else { throw OSError.lastIOError() } self.blocking = blocking } - init(fileDescriptor: Int32, blocking: Bool = false) { + init(family: Family, fileDescriptor: Int32, blocking: Bool = false) { + self.family = family self.fileDescriptor = fileDescriptor self.blocking = blocking } @@ -83,11 +119,20 @@ public final class TCPSocket { close() } + private func addressType() throws -> TCPSocketAddress.Type { + switch family { + case .v4: return sockaddr_in.self + case .v6: return sockaddr_in6.self + } + } + /// Bind the socket at given port and interface /// - Parameter port: port number to bind to /// - Parameter interface: networking interface to bind to, in IPv6 format /// - Parameter addressReusable: should we make address reusable - func bind(port: Int, interface: String = "::", addressReusable: Bool = true) throws { + func bind(port: Int, interface: String? = nil, addressReusable: Bool = true) throws { + let addressType = try self.addressType() + let interface = interface ?? addressType.loopbackName // make address reusable if addressReusable { var reuse = Int32(1) @@ -101,21 +146,12 @@ public final class TCPSocket { throw OSError.lastIOError() } } - // create IPv6 socket address - var address = sockaddr_in6() - #if !os(Linux) - address.sin6_len = UInt8(MemoryLayout.stride) - #endif - address.sin6_family = sa_family_t(AF_INET6) - address.sin6_port = UInt16(port).bigEndian - address.sin6_flowinfo = 0 - address.sin6_addr = try ipAddressToStruct(address: interface) - address.sin6_scope_id = 0 - let size = socklen_t(MemoryLayout.size) + // create socket address + var address = try addressType.from(address: interface, port: UInt16(port)).asData() // bind the address and port on socket - guard withUnsafePointer(to: &address, { pointer in - return pointer.withMemoryRebound(to: sockaddr.self, capacity: Int(size)) { pointer in - return SystemLibrary.bind(fileDescriptor, pointer, size) >= 0 + guard address.withUnsafeBytes({ (bytesPointer: UnsafePointer) in + return bytesPointer.withMemoryRebound(to: sockaddr.self, capacity: 1) { pointer in + return SystemLibrary.bind(fileDescriptor, pointer, socklen_t(address.count)) >= 0 } }) else { throw OSError.lastIOError() @@ -132,38 +168,29 @@ public final class TCPSocket { /// Accept a new connection func accept() throws -> TCPSocket { - var address = sockaddr_in6() - var size = socklen_t(MemoryLayout.size) - let clientFileDescriptor = withUnsafeMutablePointer(to: &address) { pointer in - return pointer.withMemoryRebound(to: sockaddr.self, capacity: Int(size)) { pointer in + var address = try addressType().allocate() + var size = socklen_t(0) + let clientFileDescriptor = address.withUnsafeMutableBytes { (bytesPointer: UnsafeMutablePointer) in + return bytesPointer.withMemoryRebound(to: sockaddr.self, capacity: 1) { pointer in return SystemLibrary.accept(fileDescriptor, pointer, &size) } } guard clientFileDescriptor >= 0 else { throw OSError.lastIOError() } - return TCPSocket(fileDescriptor: clientFileDescriptor) + return TCPSocket(family: family, fileDescriptor: clientFileDescriptor) } /// Connect to a peer /// - Parameter host: the target host to connect, in IPv4 or IPv6 format, like 127.0.0.1 or ::1 /// - Parameter port: the target host port number to connect - func connect(host: String, port: Int) throws { - // create IPv6 socket address - var address = sockaddr_in6() - #if !os(Linux) - address.sin6_len = UInt8(MemoryLayout.stride) - #endif - address.sin6_family = sa_family_t(AF_INET6) - address.sin6_port = UInt16(port).bigEndian - address.sin6_flowinfo = 0 - address.sin6_addr = try ipAddressToStruct(address: host) - address.sin6_scope_id = 0 - let size = socklen_t(MemoryLayout.size) - // connect to the host and port - let connectResult = withUnsafePointer(to: &address) { pointer in - return pointer.withMemoryRebound(to: sockaddr.self, capacity: Int(size)) { pointer in - return SystemLibrary.connect(fileDescriptor, pointer, size) + func connect(host: String? = nil, port: Int) throws { + let addressType = try self.addressType() + let host = host ?? addressType.loopbackName + var address = try addressType.from(address: host, port: UInt16(port)).asData() + let connectResult = address.withUnsafeBytes { (bytesPointer: UnsafePointer) in + return bytesPointer.withMemoryRebound(to: sockaddr.self, capacity: 1) { pointer in + return SystemLibrary.connect(fileDescriptor, pointer, socklen_t(address.count)) } } guard connectResult >= 0 || errno == EINPROGRESS else { @@ -263,16 +290,6 @@ public final class TCPSocket { } } - // Convert IP address to binary struct - private func ipAddressToStruct(address: String) throws -> in6_addr { - // convert interface string into IPv6 address struct - var binary: in6_addr = in6_addr() - guard address.withCString({ inet_pton(AF_INET6, $0, &binary) >= 0 }) else { - throw OSError.lastIOError() - } - return binary - } - private func structToAddress( addrStruct: StructType, family: Int32, @@ -297,3 +314,88 @@ public final class TCPSocket { return String(data: address, encoding: .utf8)! } } + + +extension TCPSocket.Family { + + var constant: Int32 { + switch self { + case .v4: return AF_INET + case .v6: return AF_INET6 + } + } + + fileprivate static func from(address: String) throws -> TCPSocket.Family { + var binary: in_addr = in_addr() + if (address.withCString { return inet_pton(AF_INET, $0, &binary) } == 1) { return .v4 } + if (address.withCString { return inet_pton(AF_INET6, $0, &binary) } == 1) { return .v6 } + throw TCPSocket.Error.unknownFamily + } + +} + + +extension sockaddr_in: TCPSocketAddress { + + public static let family = TCPSocket.Family.v4 + public static let loopbackName = "127.0.0.1" + + public func asData() -> Data { + var address = self + return withUnsafeBytes(of: &address) { + return Data(bytes: $0.baseAddress!, count: $0.count) + } + } + + public static func allocate() -> Data { + return Data(capacity: MemoryLayout.size) + } + + // convert interface string into IPv4 address struct + public static func from(address: String, port: UInt16) throws -> TCPSocketAddress { + var binary: in_addr = in_addr() + guard address.withCString({ inet_pton(AF_INET, $0, &binary) >= 0 }) else { + throw OSError.lastIOError() + } + var address = sockaddr_in() + address.sin_len = UInt8(MemoryLayout.size) + address.sin_family = UInt8(sockaddr_in.family.constant) + address.sin_port = CFSwapInt16HostToBig(port) + address.sin_addr = binary + return address + } + +} + + +extension sockaddr_in6: TCPSocketAddress { + + public static let family = TCPSocket.Family.v6 + public static let loopbackName = "::" + + public func asData() -> Data { + var address = self + return withUnsafeBytes(of: &address) { + return Data(bytes: $0.baseAddress!, count: $0.count) + } + } + + public static func allocate() -> Data { + return Data(capacity: MemoryLayout.size) + } + + // convert interface string into IPv6 address struct + public static func from(address: String, port: UInt16) throws -> TCPSocketAddress { + var binary: in6_addr = in6_addr() + guard address.withCString({ inet_pton(AF_INET6, $0, &binary) >= 0 }) else { + throw OSError.lastIOError() + } + var address = sockaddr_in6() + address.sin6_len = UInt8(MemoryLayout.size) + address.sin6_family = UInt8(sockaddr_in6.family.constant) + address.sin6_port = CFSwapInt16HostToBig(port) + address.sin6_addr = binary + return address + } + +} diff --git a/Tests/EmbassyTests/KqueueSelectorTests.swift b/Tests/EmbassyTests/KqueueSelectorTests.swift index 6b26e04..e58d917 100644 --- a/Tests/EmbassyTests/KqueueSelectorTests.swift +++ b/Tests/EmbassyTests/KqueueSelectorTests.swift @@ -17,7 +17,7 @@ class KqueueSelectorTests: XCTestCase { func testRegister() { let selector = try! KqueueSelector() - let socket = try! TCPSocket() + let socket = try! TCPSocket(family: .v6) XCTAssertNil(selector[socket.fileDescriptor]) @@ -32,7 +32,7 @@ class KqueueSelectorTests: XCTestCase { func testUnregister() { let selector = try! KqueueSelector() - let socket = try! TCPSocket() + let socket = try! TCPSocket(family: .v6) try! selector.register(socket.fileDescriptor, events: [.read], data: nil) @@ -45,7 +45,7 @@ class KqueueSelectorTests: XCTestCase { func testRegisterKeyError() { let selector = try! KqueueSelector() - let socket = try! TCPSocket() + let socket = try! TCPSocket(family: .v6) try! selector.register(socket.fileDescriptor, events: [.read], data: nil) XCTAssertThrowsError(try selector.register( @@ -66,7 +66,7 @@ class KqueueSelectorTests: XCTestCase { func testUnregisterKeyError() { let selector = try! KqueueSelector() - let socket = try! TCPSocket() + let socket = try! TCPSocket(family: .v6) XCTAssertThrowsError(try selector.unregister(socket.fileDescriptor)) { error in guard let error = error as? KqueueSelector.Error else { @@ -84,7 +84,7 @@ class KqueueSelectorTests: XCTestCase { let selector = try! KqueueSelector() let port = try! getUnusedTCPPort() - let listenSocket = try! TCPSocket() + let listenSocket = try! TCPSocket(family: .v6) try! listenSocket.bind(port: port) try! listenSocket.listen() @@ -95,7 +95,7 @@ class KqueueSelectorTests: XCTestCase { XCTAssertEqual(try! selector.select(timeout: 2.0).count, 0) } - let clientSocket = try! TCPSocket() + let clientSocket = try! TCPSocket(family: .v6) // make a connect 1 seconds later queue.asyncAfter(deadline: DispatchTime.now() + Double(Int64(1 * NSEC_PER_SEC)) / Double(NSEC_PER_SEC)) { @@ -115,7 +115,7 @@ class KqueueSelectorTests: XCTestCase { let selector = try! KqueueSelector() let port = try! getUnusedTCPPort() - let listenSocket = try! TCPSocket() + let listenSocket = try! TCPSocket(family: .v6) try! listenSocket.bind(port: port) try! listenSocket.listen() @@ -123,7 +123,7 @@ class KqueueSelectorTests: XCTestCase { XCTAssertEqual(try! selector.select(timeout: 1.0).count, 0) - let clientSocket = try! TCPSocket() + let clientSocket = try! TCPSocket(family: .v6) // make a connect 1 seconds later queue.asyncAfter(deadline: DispatchTime.now() + Double(Int64(1 * NSEC_PER_SEC)) / Double(NSEC_PER_SEC)) { try! clientSocket.connect(host: "::1", port: port) @@ -137,13 +137,13 @@ class KqueueSelectorTests: XCTestCase { let selector = try! KqueueSelector() let port = try! getUnusedTCPPort() - let listenSocket = try! TCPSocket() + let listenSocket = try! TCPSocket(family: .v6) try! listenSocket.bind(port: port) try! listenSocket.listen() try! selector.register(listenSocket.fileDescriptor, events: [.read], data: nil) - let clientSocket = try! TCPSocket() + let clientSocket = try! TCPSocket(family: .v6) // make a connect 1 seconds later queue.asyncAfter(deadline: DispatchTime.now() + Double(Int64(1 * NSEC_PER_SEC)) / Double(NSEC_PER_SEC)) { try! clientSocket.connect(host: "::1", port: port) @@ -159,7 +159,7 @@ class KqueueSelectorTests: XCTestCase { try! selector.unregister(listenSocket.fileDescriptor) - let clientSocket2 = try! TCPSocket() + let clientSocket2 = try! TCPSocket(family: .v6) // make a connect 1 seconds later queue.asyncAfter( deadline: DispatchTime.now() + Double(Int64(1 * NSEC_PER_SEC)) / Double(NSEC_PER_SEC) @@ -177,9 +177,9 @@ class KqueueSelectorTests: XCTestCase { let port = try! getUnusedTCPPort() - let clientSocket = try! TCPSocket() + let clientSocket = try! TCPSocket(family: .v6) - let listenSocket = try! TCPSocket() + let listenSocket = try! TCPSocket(family: .v6) try! listenSocket.bind(port: port) try! listenSocket.listen() diff --git a/Tests/EmbassyTests/SelectSelectorTests.swift b/Tests/EmbassyTests/SelectSelectorTests.swift index 6603c92..9f91c92 100644 --- a/Tests/EmbassyTests/SelectSelectorTests.swift +++ b/Tests/EmbassyTests/SelectSelectorTests.swift @@ -32,7 +32,7 @@ class SelectSelectorTests: XCTestCase { func testRegister() { let selector = try! SelectSelector() - let socket = try! TCPSocket() + let socket = try! TCPSocket(family: .v6) XCTAssertNil(selector[socket.fileDescriptor]) @@ -47,7 +47,7 @@ class SelectSelectorTests: XCTestCase { func testUnregister() { let selector = try! SelectSelector() - let socket = try! TCPSocket() + let socket = try! TCPSocket(family: .v6) try! selector.register(socket.fileDescriptor, events: [.read], data: nil) @@ -60,7 +60,7 @@ class SelectSelectorTests: XCTestCase { func testRegisterKeyError() { let selector = try! SelectSelector() - let socket = try! TCPSocket() + let socket = try! TCPSocket(family: .v6) try! selector.register(socket.fileDescriptor, events: [.read], data: nil) XCTAssertThrowsError(try selector.register( @@ -81,7 +81,7 @@ class SelectSelectorTests: XCTestCase { func testUnregisterKeyError() { let selector = try! SelectSelector() - let socket = try! TCPSocket() + let socket = try! TCPSocket(family: .v6) XCTAssertThrowsError(try selector.unregister(socket.fileDescriptor)) { error in guard let error = error as? SelectSelector.Error else { @@ -99,7 +99,7 @@ class SelectSelectorTests: XCTestCase { let selector = try! SelectSelector() let port = try! getUnusedTCPPort() - let listenSocket = try! TCPSocket() + let listenSocket = try! TCPSocket(family: .v6) try! listenSocket.bind(port: port) try! listenSocket.listen() @@ -110,7 +110,7 @@ class SelectSelectorTests: XCTestCase { XCTAssertEqual(try! selector.select(timeout: 2.0).count, 0) } - let clientSocket = try! TCPSocket() + let clientSocket = try! TCPSocket(family: .v6) let emptyIOEvents = assertExecutingTime(1, accuracy: 1) { return try! selector.select(timeout: 1.0) @@ -135,7 +135,7 @@ class SelectSelectorTests: XCTestCase { let selector = try! SelectSelector() let port = try! getUnusedTCPPort() - let listenSocket = try! TCPSocket() + let listenSocket = try! TCPSocket(family: .v6) try! listenSocket.bind(port: port) try! listenSocket.listen() @@ -143,7 +143,7 @@ class SelectSelectorTests: XCTestCase { XCTAssertEqual(try! selector.select(timeout: 1.0).count, 0) - let clientSocket = try! TCPSocket() + let clientSocket = try! TCPSocket(family: .v6) // make a connect 1 seconds later queue.asyncAfter(deadline: DispatchTime.now() + Double(Int64(1 * NSEC_PER_SEC)) / Double(NSEC_PER_SEC)) { try! clientSocket.connect(host: "::1", port: port) @@ -157,13 +157,13 @@ class SelectSelectorTests: XCTestCase { let selector = try! SelectSelector() let port = try! getUnusedTCPPort() - let listenSocket = try! TCPSocket() + let listenSocket = try! TCPSocket(family: .v6) try! listenSocket.bind(port: port) try! listenSocket.listen() try! selector.register(listenSocket.fileDescriptor, events: [.read], data: nil) - let clientSocket = try! TCPSocket() + let clientSocket = try! TCPSocket(family: .v6) // make a connect 1 seconds later queue.asyncAfter(deadline: DispatchTime.now() + Double(Int64(1 * NSEC_PER_SEC)) / Double(NSEC_PER_SEC)) { try! clientSocket.connect(host: "::1", port: port) @@ -179,7 +179,7 @@ class SelectSelectorTests: XCTestCase { try! selector.unregister(listenSocket.fileDescriptor) - let clientSocket2 = try! TCPSocket() + let clientSocket2 = try! TCPSocket(family: .v6) // make a connect 1 seconds later queue.asyncAfter( deadline: DispatchTime.now() + Double(Int64(1 * NSEC_PER_SEC)) / Double(NSEC_PER_SEC) @@ -197,9 +197,9 @@ class SelectSelectorTests: XCTestCase { let port = try! getUnusedTCPPort() - let clientSocket = try! TCPSocket() + let clientSocket = try! TCPSocket(family: .v6) - let listenSocket = try! TCPSocket() + let listenSocket = try! TCPSocket(family: .v6) try! listenSocket.bind(port: port) try! listenSocket.listen() try! selector.register(listenSocket.fileDescriptor, events: [.read, .write], data: nil) diff --git a/Tests/EmbassyTests/SelectorEventLoopTests.swift b/Tests/EmbassyTests/SelectorEventLoopTests.swift index 23cbd00..57b6d86 100644 --- a/Tests/EmbassyTests/SelectorEventLoopTests.swift +++ b/Tests/EmbassyTests/SelectorEventLoopTests.swift @@ -124,7 +124,7 @@ class SelectorEventLoopTests: XCTestCase { func testSetReader() { let port = try! getUnusedTCPPort() - let listenSocket = try! TCPSocket() + let listenSocket = try! TCPSocket(family: .v6) try! listenSocket.bind(port: port) try! listenSocket.listen() var readerCalled = false @@ -134,7 +134,7 @@ class SelectorEventLoopTests: XCTestCase { self.loop.stop() } - let clientSocket = try! TCPSocket() + let clientSocket = try! TCPSocket(family: .v6) // make a connection 1 seconds later loop.call(withDelay: 1) { @@ -149,12 +149,12 @@ class SelectorEventLoopTests: XCTestCase { func testSetWriter() { let port = try! getUnusedTCPPort() - let listenSocket = try! TCPSocket() + let listenSocket = try! TCPSocket(family: .v6) try! listenSocket.bind(port: port) try! listenSocket.listen() var writerCalled = false - let clientSocket = try! TCPSocket() + let clientSocket = try! TCPSocket(family: .v6) // make a connect 1 seconds later loop.call(withDelay: 1) { [unowned self] in @@ -177,11 +177,11 @@ class SelectorEventLoopTests: XCTestCase { func testRemoveReader() { let port = try! getUnusedTCPPort() - let listenSocket = try! TCPSocket() + let listenSocket = try! TCPSocket(family: .v6) try! listenSocket.bind(port: port) try! listenSocket.listen() - let clientSocket = try! TCPSocket() + let clientSocket = try! TCPSocket(family: .v6) var acceptedSocket: TCPSocket! var readData = [String]() diff --git a/Tests/EmbassyTests/TCPSocketTests.swift b/Tests/EmbassyTests/TCPSocketTests.swift index 82173d2..f93a3b0 100644 --- a/Tests/EmbassyTests/TCPSocketTests.swift +++ b/Tests/EmbassyTests/TCPSocketTests.swift @@ -26,9 +26,9 @@ import XCTest class TCPSocketTests: XCTestCase { let queue = DispatchQueue(label: "com.envoy.embassy-tests.tcp-sockets", attributes: []) - func testAccept() { + func testAccept4() { let port = try! getUnusedTCPPort() - let listenSocket = try! TCPSocket(blocking: true) + let listenSocket = try! TCPSocket(family: .v4, blocking: true) try! listenSocket.bind(port: port) try! listenSocket.listen() @@ -39,7 +39,114 @@ class TCPSocketTests: XCTestCase { exp0.fulfill() } - let clientSocket = try! TCPSocket() + let clientSocket = try! TCPSocket(family: .v4) + try! clientSocket.connect(port: port) + + waitForExpectations(timeout: 3) { error in + XCTAssertNil(error) + } + XCTAssertNotNil(acceptedSocket) + } + + func testReadAndWrite4() { + let port = try! getUnusedTCPPort() + let listenSocket = try! TCPSocket(family: .v4, blocking: true) + try! listenSocket.bind(port: port) + try! listenSocket.listen() + + let exp0 = expectation(description: "socket accepcted") + var acceptedSocket: TCPSocket! + queue.async { + acceptedSocket = try! listenSocket.accept() + exp0.fulfill() + } + + let clientSocket = try! TCPSocket(family: .v4, blocking: true) + try! clientSocket.connect(port: port) + + waitForExpectations(timeout: 4) { error in + XCTAssertNil(error) + } + + let stringToSend = "hello baby" + let bytesToSend = Data(stringToSend.utf8) + + var receivedData: Data? + let exp1 = expectation(description: "socket received") + + let sentBytes = try! clientSocket.send(data: bytesToSend) + XCTAssertEqual(sentBytes, bytesToSend.count) + + queue.async { + receivedData = try! acceptedSocket.recv(size: 1024) + exp1.fulfill() + } + + waitForExpectations(timeout: 3) { error in + XCTAssertNil(error) + } + + XCTAssertEqual(String(bytes: receivedData!, encoding: String.Encoding.utf8), stringToSend) + } + + func testGetPeerName4() { + let port = try! getUnusedTCPPort() + let listenSocket = try! TCPSocket(family: .v4, blocking: true) + try! listenSocket.bind(port: port) + try! listenSocket.listen() + + let exp0 = expectation(description: "socket accepcted") + var acceptedSocket: TCPSocket! + queue.async { + acceptedSocket = try! listenSocket.accept() + exp0.fulfill() + } + + let clientSocket = try! TCPSocket(family: .v4, blocking: true) + try! clientSocket.connect(port: port) + + waitForExpectations(timeout: 4, handler: nil) + + XCTAssertEqual(try! acceptedSocket.getPeerName().0, "127.0.0.1") + XCTAssertEqual(try! clientSocket.getPeerName().0, "127.0.0.1") + } + + func testGetSockName4() { + let port = try! getUnusedTCPPort() + let listenSocket = try! TCPSocket(family: .v4, blocking: true) + try! listenSocket.bind(port: port) + try! listenSocket.listen() + + let exp0 = expectation(description: "socket accepcted") + var acceptedSocket: TCPSocket! + queue.async { + acceptedSocket = try! listenSocket.accept() + exp0.fulfill() + } + + let clientSocket = try! TCPSocket(family: .v4, blocking: true) + try! clientSocket.connect(host: "127.0.0.1", port: port) + + waitForExpectations(timeout: 4, handler: nil) + + XCTAssertEqual(try! acceptedSocket.getSockName().0, "127.0.0.1") + XCTAssertEqual(try! clientSocket.getSockName().0, "127.0.0.1") + } + + func testAccept6() { + let port = try! getUnusedTCPPort() + let listenSocket = try! TCPSocket(family: .v6, blocking: true) + try! listenSocket.bind(port: port) + try! listenSocket.listen() + + let exp0 = expectation(description: "socket accepcted") + var acceptedSocket: TCPSocket! + queue.async { + acceptedSocket = try! listenSocket.accept() + exp0.fulfill() + } + + let clientSocket = try! TCPSocket(family: .v6) try! clientSocket.connect(host: "::1", port: port) waitForExpectations(timeout: 3) { error in @@ -48,9 +155,9 @@ class TCPSocketTests: XCTestCase { XCTAssertNotNil(acceptedSocket) } - func testReadAndWrite() { + func testReadAndWrite6() { let port = try! getUnusedTCPPort() - let listenSocket = try! TCPSocket(blocking: true) + let listenSocket = try! TCPSocket(family: .v6, blocking: true) try! listenSocket.bind(port: port) try! listenSocket.listen() @@ -61,7 +168,7 @@ class TCPSocketTests: XCTestCase { exp0.fulfill() } - let clientSocket = try! TCPSocket(blocking: true) + let clientSocket = try! TCPSocket(family: .v6, blocking: true) try! clientSocket.connect(host: "::1", port: port) waitForExpectations(timeout: 4) { error in @@ -89,9 +196,9 @@ class TCPSocketTests: XCTestCase { XCTAssertEqual(String(bytes: receivedData!, encoding: String.Encoding.utf8), stringToSend) } - func testGetPeerName() { + func testGetPeerName6() { let port = try! getUnusedTCPPort() - let listenSocket = try! TCPSocket(blocking: true) + let listenSocket = try! TCPSocket(family: .v6, blocking: true) try! listenSocket.bind(port: port) try! listenSocket.listen() @@ -102,7 +209,7 @@ class TCPSocketTests: XCTestCase { exp0.fulfill() } - let clientSocket = try! TCPSocket(blocking: true) + let clientSocket = try! TCPSocket(family: .v6, blocking: true) try! clientSocket.connect(host: "::1", port: port) waitForExpectations(timeout: 4, handler: nil) @@ -111,9 +218,9 @@ class TCPSocketTests: XCTestCase { XCTAssertEqual(try! clientSocket.getPeerName().0, "::1") } - func testGetSockName() { + func testGetSockName6() { let port = try! getUnusedTCPPort() - let listenSocket = try! TCPSocket(blocking: true) + let listenSocket = try! TCPSocket(family: .v6, blocking: true) try! listenSocket.bind(port: port) try! listenSocket.listen() @@ -124,7 +231,7 @@ class TCPSocketTests: XCTestCase { exp0.fulfill() } - let clientSocket = try! TCPSocket(blocking: true) + let clientSocket = try! TCPSocket(family: .v6, blocking: true) try! clientSocket.connect(host: "::1", port: port) waitForExpectations(timeout: 4, handler: nil) diff --git a/Tests/EmbassyTests/TransportTests.swift b/Tests/EmbassyTests/TransportTests.swift index c90ab53..17ad8df 100644 --- a/Tests/EmbassyTests/TransportTests.swift +++ b/Tests/EmbassyTests/TransportTests.swift @@ -29,7 +29,7 @@ class TransportTests: XCTestCase { let loop = try! SelectorEventLoop(selector: try! TestingSelector()) let port = try! getUnusedTCPPort() - let listenSocket = try! TCPSocket() + let listenSocket = try! TCPSocket(family: .v6) try! listenSocket.bind(port: port) try! listenSocket.listen() @@ -51,7 +51,7 @@ class TransportTests: XCTestCase { dataChunk6 ].reduce(0) { $0 + $1.characters.count } - let clientSocket = try! TCPSocket() + let clientSocket = try! TCPSocket(family: .v6) let clientTransport = Transport(socket: clientSocket, eventLoop: loop) { data in clientReceivedData.append(String(bytes: data, encoding: String.Encoding.utf8)!) totalReceivedSize += clientReceivedData.last!.characters.count @@ -117,14 +117,14 @@ class TransportTests: XCTestCase { let loop = try! SelectorEventLoop(selector: try! TestingSelector()) let port = try! getUnusedTCPPort() - let listenSocket = try! TCPSocket() + let listenSocket = try! TCPSocket(family: .v6) try! listenSocket.bind(port: port) try! listenSocket.listen() var clientReceivedData: [String] = [] var serverReceivedData: [String] = [] - let clientSocket = try! TCPSocket() + let clientSocket = try! TCPSocket(family: .v6) let clientTransport = Transport(socket: clientSocket, eventLoop: loop) { data in clientReceivedData.append(String(bytes: data, encoding: String.Encoding.utf8)!) if clientReceivedData.count >= 3 && serverReceivedData.count >= 3 { @@ -179,11 +179,11 @@ class TransportTests: XCTestCase { let loop = try! SelectorEventLoop(selector: try! TestingSelector()) let port = try! getUnusedTCPPort() - let listenSocket = try! TCPSocket() + let listenSocket = try! TCPSocket(family: .v6) try! listenSocket.bind(port: port) try! listenSocket.listen() - let clientSocket = try! TCPSocket() + let clientSocket = try! TCPSocket(family: .v6) let clientTransport = Transport(socket: clientSocket, eventLoop: loop) { _ in } @@ -243,14 +243,14 @@ class TransportTests: XCTestCase { let loop = try! SelectorEventLoop(selector: try! TestingSelector()) let port = try! getUnusedTCPPort() - let listenSocket = try! TCPSocket() + let listenSocket = try! TCPSocket(family: .v6) try! listenSocket.bind(port: port) try! listenSocket.listen() var clientReceivedData: [String] = [] var serverReceivedData: [String] = [] - let clientSocket = try! TCPSocket() + let clientSocket = try! TCPSocket(family: .v6) let clientTransport = Transport(socket: clientSocket, eventLoop: loop) { data in clientReceivedData.append(String(bytes: data, encoding: String.Encoding.utf8)!) if clientReceivedData.count >= 3 && serverReceivedData.count >= 3 {