diff --git a/Sources/Connection.swift b/Sources/Connection.swift index 74c9364..5659013 100644 --- a/Sources/Connection.swift +++ b/Sources/Connection.swift @@ -1,2 +1 @@ -public protocol Connection : ReadableFileDescriptor, WritableFileDescriptor { -} +public protocol Connection : ReadableFileDescriptor, WritableFileDescriptor {} diff --git a/Sources/FDSet.swift b/Sources/FDSet.swift index b3bc3ab..27dd738 100644 --- a/Sources/FDSet.swift +++ b/Sources/FDSet.swift @@ -6,20 +6,20 @@ import Darwin func fdZero(_ set: inout fd_set) { -#if os(Linux) - set.__fds_bits = (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) -#else - set.fds_bits = (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) -#endif + #if os(Linux) + set.__fds_bits = (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) + #else + set.fds_bits = (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) + #endif } func fdSet(_ descriptor: FileNumber, _ set: inout fd_set) { -#if os(Linux) - let intOffset = Int(descriptor / 16) - let bitOffset = Int(descriptor % 16) - let mask = 1 << bitOffset - switch intOffset { + #if os(Linux) + let intOffset = Int(descriptor / 16) + let bitOffset = Int(descriptor % 16) + let mask = 1 << bitOffset + switch intOffset { case 0: set.__fds_bits.0 = set.__fds_bits.0 | mask case 1: set.__fds_bits.1 = set.__fds_bits.1 | mask case 2: set.__fds_bits.2 = set.__fds_bits.2 | mask @@ -37,13 +37,13 @@ func fdSet(_ descriptor: FileNumber, _ set: inout fd_set) { case 14: set.__fds_bits.14 = set.__fds_bits.14 | mask case 15: set.__fds_bits.15 = set.__fds_bits.15 | mask default: break - } -#else - let intOffset = Int32(descriptor / 16) - let bitOffset = Int32(descriptor % 16) - let mask: Int32 = 1 << bitOffset - - switch intOffset { + } + #else + let intOffset = Int32(descriptor / 16) + let bitOffset = Int32(descriptor % 16) + let mask: Int32 = 1 << bitOffset + + switch intOffset { case 0: set.fds_bits.0 = set.fds_bits.0 | mask case 1: set.fds_bits.1 = set.fds_bits.1 | mask case 2: set.fds_bits.2 = set.fds_bits.2 | mask @@ -61,18 +61,18 @@ func fdSet(_ descriptor: FileNumber, _ set: inout fd_set) { case 14: set.fds_bits.14 = set.fds_bits.14 | mask case 15: set.fds_bits.15 = set.fds_bits.15 | mask default: break - } -#endif + } + #endif } func fdIsSet(_ descriptor: FileNumber, _ set: inout fd_set) -> Bool { -#if os(Linux) - let intOffset = Int(descriptor / 32) - let bitOffset = Int(descriptor % 32) - let mask = Int(1 << bitOffset) - - switch intOffset { + #if os(Linux) + let intOffset = Int(descriptor / 32) + let bitOffset = Int(descriptor % 32) + let mask = Int(1 << bitOffset) + + switch intOffset { case 0: return set.__fds_bits.0 & mask != 0 case 1: return set.__fds_bits.1 & mask != 0 case 2: return set.__fds_bits.2 & mask != 0 @@ -90,13 +90,13 @@ func fdIsSet(_ descriptor: FileNumber, _ set: inout fd_set) -> Bool { case 14: return set.__fds_bits.14 & mask != 0 case 15: return set.__fds_bits.15 & mask != 0 default: return false - } -#else - let intOffset = Int32(descriptor / 32) - let bitOffset = Int32(descriptor % 32) - let mask = Int32(1 << bitOffset) - - switch intOffset { + } + #else + let intOffset = Int32(descriptor / 32) + let bitOffset = Int32(descriptor % 32) + let mask = Int32(1 << bitOffset) + + switch intOffset { case 0: return set.fds_bits.0 & mask != 0 case 1: return set.fds_bits.1 & mask != 0 case 2: return set.fds_bits.2 & mask != 0 @@ -130,6 +130,6 @@ func fdIsSet(_ descriptor: FileNumber, _ set: inout fd_set) -> Bool { case 30: return set.fds_bits.30 & mask != 0 case 31: return set.fds_bits.31 & mask != 0 default: return false - } -#endif + } + #endif } diff --git a/Sources/FileDescriptor.swift b/Sources/FileDescriptor.swift index 11d82ac..e9bda4e 100644 --- a/Sources/FileDescriptor.swift +++ b/Sources/FileDescriptor.swift @@ -7,32 +7,50 @@ private let system_close = Darwin.close #endif -public typealias Byte = Int8 +public typealias Byte = UInt8 public typealias FileNumber = Int32 public protocol FileDescriptor { - var fileNumber: FileNumber { get } + var fileNumber: FileNumber { get } } - struct FileDescriptorError : Error { + enum ErrorKind: String { + case readError, writeError, selectError, pipeError, closeError, unknown + } + + let kind: ErrorKind + let message: String? + + var localizedDescription: String { + "FileDescriptorError of kind \(kind.rawValue)\(message != nil ? "\nmessage: \(message!)" : "")" + } + + init(kind: ErrorKind, message: String? = nil) { + self.kind = kind + self.message = message + } + + init(kind: ErrorKind, errno: Int32) { + let message = String(utf8String: strerror(errno)) + self.init(kind: kind, message: message) + } } - extension FileDescriptor { - /// Close deletes the file descriptor from the per-process object reference table - public func close() throws { - if system_close(fileNumber) == -1 { - throw FileDescriptorError() + /// Close deletes the file descriptor from the per-process object reference table + public func close() throws { + if system_close(fileNumber) == -1 { + throw FileDescriptorError(kind: .closeError, errno: errno) + } } - } - - public var isClosed: Bool { - if fcntl(fileNumber, F_GETFL) == -1 { - return errno == EBADF + + public var isClosed: Bool { + if fcntl(fileNumber, F_GETFL) == -1 { + return errno == EBADF + } + + return false } - - return false - } } diff --git a/Sources/Listener.swift b/Sources/Listener.swift index 60e1846..ffcf27f 100644 --- a/Sources/Listener.swift +++ b/Sources/Listener.swift @@ -1,3 +1,5 @@ public protocol Listener : FileDescriptor { - func accept() throws -> Connection + associatedtype AnyConnection + + func accept() throws -> AnyConnection } diff --git a/Sources/Pipe.swift b/Sources/Pipe.swift index 8e419e4..4bc1f1a 100644 --- a/Sources/Pipe.swift +++ b/Sources/Pipe.swift @@ -8,35 +8,35 @@ private let system_pipe = Darwin.pipe class PipeReadFileDescriptor : ReadableFileDescriptor { - let fileNumber: FileNumber - - init(fileNumber: FileNumber) { - self.fileNumber = fileNumber - } - - deinit { - let _ = try? close() - } + let fileNumber: FileNumber + + init(fileNumber: FileNumber) { + self.fileNumber = fileNumber + } + + deinit { + let _ = try? close() + } } class PipeWriteFileDescriptor : WritableFileDescriptor { - let fileNumber: FileNumber - - init(fileNumber: FileNumber) { - self.fileNumber = fileNumber - } - - deinit { - let _ = try? close() - } + let fileNumber: FileNumber + + init(fileNumber: FileNumber) { + self.fileNumber = fileNumber + } + + deinit { + let _ = try? close() + } } public func pipe() throws -> (reader: ReadableFileDescriptor, writer: WritableFileDescriptor) { - var fileNumbers: [FileNumber] = [0, 0] - if system_pipe(&fileNumbers) == -1 { - throw FileDescriptorError() - } - return (PipeReadFileDescriptor(fileNumber: fileNumbers[0]), PipeWriteFileDescriptor(fileNumber: fileNumbers[1])) + var fileNumbers: [FileNumber] = [0, 0] + if system_pipe(&fileNumbers) == -1 { + throw FileDescriptorError(kind: .pipeError, errno: errno) + } + return (PipeReadFileDescriptor(fileNumber: fileNumbers[0]), PipeWriteFileDescriptor(fileNumber: fileNumbers[1])) } diff --git a/Sources/ReadableFileDescriptor.swift b/Sources/ReadableFileDescriptor.swift index 7fa0c98..db3f4ce 100644 --- a/Sources/ReadableFileDescriptor.swift +++ b/Sources/ReadableFileDescriptor.swift @@ -1,3 +1,4 @@ +import Foundation #if os(Linux) import Glibc private let system_read = Glibc.read @@ -6,25 +7,45 @@ import Darwin private let system_read = Darwin.read #endif - -public protocol ReadableFileDescriptor : FileDescriptor { -} - +public protocol ReadableFileDescriptor : FileDescriptor {} extension ReadableFileDescriptor { - /// Read attempts to read the given size from the file descriptor - public func read(_ bufferSize: Int) throws -> [Byte] { - let buffer = UnsafeMutableRawPointer(malloc(bufferSize)) - defer { free(buffer) } - let size = system_read(fileNumber, buffer!, bufferSize) - - if size > 0 { - let readSize = min(size, bufferSize) - var bytes = [Byte](repeating: 0, count: readSize) - memcpy(&bytes, buffer!, readSize) - return bytes + /// Read attempts to read the given size from the file descriptor + public func read(_ bufferSize: Int) throws -> [Byte] { + let buffer = UnsafeMutableRawPointer(malloc(bufferSize)) + defer { free(buffer) } + let size = system_read(fileNumber, buffer!, bufferSize) + + guard size != -1 else { + throw FileDescriptorError(kind: .readError, errno: errno) + } + + let readSize = min(size, bufferSize) + var bytes = [Byte](repeating: 0, count: readSize) + memcpy(&bytes, buffer!, readSize) + return bytes + } + + /// Read attempts to read the given size from the file descriptor + public func read(_ bufferSize: Int) throws -> Data { + let bytes: [Byte] = try read(bufferSize) + + return Data(bytes: bytes, count: bytes.count) + } + + public func readAll() throws -> Data { + var result = Data() + var data = CChar() + var data_read: size_t + + while (((data_read = recv(fileNumber, &data, 1, 0)), data_read > 0).1 && !Character(UnicodeScalar(UInt8(bitPattern: data))).isNewline) { + result.append(contentsOf: [data].map(UInt8.init)) + } + + guard data_read != -1 else { + throw FileDescriptorError(kind: .unknown, errno: errno) + } + + return result } - - throw FileDescriptorError() - } } diff --git a/Sources/TCPConnection.swift b/Sources/TCPConnection.swift index 05eb0c5..536f569 100644 --- a/Sources/TCPConnection.swift +++ b/Sources/TCPConnection.swift @@ -1,7 +1,7 @@ public class TCPConnection : FileDescriptor, Connection { - public let fileNumber: FileNumber - - public init(fileNumber: FileNumber) { - self.fileNumber = fileNumber - } + public let fileNumber: FileNumber + + public init(fileNumber: FileNumber) { + self.fileNumber = fileNumber + } } diff --git a/Sources/TCPListener.swift b/Sources/TCPListener.swift index f67f52d..5c85ced 100644 --- a/Sources/TCPListener.swift +++ b/Sources/TCPListener.swift @@ -12,67 +12,54 @@ private let system_bind = Darwin.bind private let sock_stream = SOCK_STREAM #endif - -public class TCPListener : FileDescriptor { - public let fileNumber: FileNumber - - init(fileNumber: FileNumber) { - self.fileNumber = fileNumber - } - - public init(address: String, port: UInt16) throws { - fileNumber = socket(AF_INET, sock_stream, 0) - if fileNumber == -1 { - throw FileDescriptorError() +public class TCPListener : UNIXSocket, Listener { + + public init(address: String, port: UInt16) throws { + try super.init(kind: AF_INET) + + do { + try bind(address, port: port) + } catch { + try close() + throw error + } } - - do { - try bind(address, port: port) - } catch { - try close() - throw error + + private func bind(_ address: String, port: UInt16) throws { + var addr = sockaddr_in() + addr.sin_family = sa_family_t(AF_INET) + addr.sin_port = in_port_t(htons(in_port_t(port))) + addr.sin_addr = in_addr(s_addr: address.withCString { inet_addr($0) }) + addr.sin_zero = (0, 0, 0, 0, 0, 0, 0, 0) + + let len = socklen_t(UInt8(MemoryLayout.size)) + + try withUnsafePointer(to: &addr) { + try $0.withMemoryRebound(to: sockaddr.self, capacity: 1) { + guard system_bind(fileNumber, $0, len) != -1 else { + throw UNIXSocketError(kind: .bindError, errno: errno) + } + } + } } - } - - deinit { - let _ = try? close() - } - - fileprivate func bind(_ address: String, port: UInt16) throws { - var addr = sockaddr_in() - addr.sin_family = sa_family_t(AF_INET) - addr.sin_port = in_port_t(htons(in_port_t(port))) - addr.sin_addr = in_addr(s_addr: address.withCString { inet_addr($0) }) - addr.sin_zero = (0, 0, 0, 0, 0, 0, 0, 0) - - let len = socklen_t(UInt8(MemoryLayout.size)) - - try withUnsafePointer(to: &addr) { - try $0.withMemoryRebound(to: sockaddr.self, capacity: 1) { - guard system_bind(fileNumber, $0, len) != -1 else { - throw FileDescriptorError() + + private func listen(backlog: Int32) throws { + guard system_listen(fileNumber, backlog) != -1 else { + throw UNIXSocketError(kind: .listenError, errno: errno) } - } } - } - - fileprivate func listen(backlog: Int32) throws { - if system_listen(fileNumber, backlog) == -1 { - throw FileDescriptorError() + + private func htons(_ value: CUnsignedShort) -> CUnsignedShort { + return (value << 8) + (value >> 8) } - } - - fileprivate func htons(_ value: CUnsignedShort) -> CUnsignedShort { - return (value << 8) + (value >> 8) - } - - /// Accepts a connection socket - open func accept() throws -> TCPConnection { - let fileNumber = system_accept(self.fileNumber, nil, nil) - if fileNumber == -1 { - throw FileDescriptorError() + + /// Accepts a connection socket + public func accept() throws -> TCPConnection { + let fileNumber = system_accept(self.fileNumber, nil, nil) + guard fileNumber != -1 else { + throw UNIXSocketError(kind: .acceptError, errno: errno) + } + + return TCPConnection(fileNumber: fileNumber) } - - return TCPConnection(fileNumber: fileNumber) - } } diff --git a/Sources/UNIXClientSocket.swift b/Sources/UNIXClientSocket.swift new file mode 100644 index 0000000..4c5c069 --- /dev/null +++ b/Sources/UNIXClientSocket.swift @@ -0,0 +1,55 @@ +import Foundation +#if os(Linux) +import Glibc +private let system_accept = Glibc.accept +private let system_listen = Glibc.listen +private let system_connect = Glibc.connect +#else +import Darwin +private let system_accept = Darwin.accept +private let system_listen = Darwin.listen +private let system_connect = Darwin.connect +#endif + +public class UNIXClientSocket: UNIXSocket, Listener { + + override public init(path: URL) throws { + try super.init(path: path) + + do { + try connect(path) + } catch { + try close() + throw error + } + } + + private func connect(_ path: URL) throws { + var addr = sockaddr_un() + addr.sun_family = sa_family_t(AF_UNIX) + + let lengthOfPath = path.relativePath.withCString { Int(strlen($0)) } + + guard lengthOfPath < MemoryLayout.size(ofValue: addr.sun_path) else { + throw UNIXSocketError(kind: .pathLength, message: "Path too long!") + } + + _ = withUnsafeMutablePointer(to: &addr.sun_path.0) { pointer in + path.relativePath.withCString { + strncpy(pointer, $0, lengthOfPath) + } + } + + try withUnsafePointer(to: &addr) { pointer in + try pointer.withMemoryRebound(to: sockaddr.self, capacity: 1) { + guard system_connect(fileNumber, $0, UInt32(MemoryLayout.stride)) != -1 else { + throw UNIXSocketError(kind: .connectError, errno: errno) + } + } + } + } + + public func accept() throws -> UNIXConnection { + return UNIXConnection(fileNumber: fileNumber) + } +} diff --git a/Sources/UNIXConnection.swift b/Sources/UNIXConnection.swift index 2f59971..cdb4ef4 100644 --- a/Sources/UNIXConnection.swift +++ b/Sources/UNIXConnection.swift @@ -1,7 +1,7 @@ public class UNIXConnection : FileDescriptor, Connection { - public let fileNumber: FileNumber - - init(fileNumber: FileNumber) { - self.fileNumber = fileNumber - } + public let fileNumber: FileNumber + + init(fileNumber: FileNumber) { + self.fileNumber = fileNumber + } } diff --git a/Sources/UNIXListener.swift b/Sources/UNIXListener.swift deleted file mode 100644 index e18e6ef..0000000 --- a/Sources/UNIXListener.swift +++ /dev/null @@ -1,77 +0,0 @@ -#if os(Linux) -import Glibc -private let system_accept = Glibc.accept -private let system_listen = Glibc.listen -private let sock_stream = Int32(SOCK_STREAM.rawValue) -private let system_bind = Glibc.bind -#else -import Darwin -private let system_accept = Darwin.accept -private let system_listen = Darwin.listen -private let sock_stream = SOCK_STREAM -private let system_bind = Darwin.bind -#endif - - -public class UNIXListener : FileDescriptor { - public let fileNumber: FileNumber - - public init(path: String) throws { - fileNumber = socket(AF_UNIX, sock_stream, 0) - if fileNumber == -1 { - throw FileDescriptorError() - } - - do { - try bind(path) - } catch { - try close() - throw error - } - } - - deinit { - let _ = try? close() - } - - fileprivate func bind(_ path: String) throws { - var addr = sockaddr_un() - addr.sun_family = sa_family_t(AF_UNIX) - - let lengthOfPath = path.withCString { Int(strlen($0)) } - - guard lengthOfPath < MemoryLayout.size(ofValue: addr.sun_path) else { - throw FileDescriptorError() - } - - _ = withUnsafeMutablePointer(to: &addr.sun_path.0) { ptr in - path.withCString { - strncpy(ptr, $0, lengthOfPath) - } - } - - try withUnsafePointer(to: &addr) { - try $0.withMemoryRebound(to: sockaddr.self, capacity: 1) { - guard system_bind(fileNumber, $0, UInt32(MemoryLayout.stride)) != -1 else { - throw FileDescriptorError() - } - } - } - } - - fileprivate func listen(backlog: Int32) throws { - if system_listen(fileNumber, backlog) == -1 { - throw FileDescriptorError() - } - } - - /// Accepts a connection socket - public func accept() throws -> UNIXConnection { - let fileNumber = system_accept(self.fileNumber, nil, nil) - if fileNumber == -1 { - throw FileDescriptorError() - } - - return UNIXConnection(fileNumber: fileNumber) - } -} diff --git a/Sources/UNIXServerSocket.swift b/Sources/UNIXServerSocket.swift new file mode 100644 index 0000000..29e5785 --- /dev/null +++ b/Sources/UNIXServerSocket.swift @@ -0,0 +1,70 @@ +import Foundation +#if os(Linux) +import Glibc +private let system_accept = Glibc.accept +private let system_listen = Glibc.listen +private let sock_stream = Int32(SOCK_STREAM.rawValue) +private let system_bind = Glibc.bind +#else +import Darwin +private let system_accept = Darwin.accept +private let system_listen = Darwin.listen +private let sock_stream = SOCK_STREAM +private let system_bind = Darwin.bind +#endif + + +public class UNIXServerSocket: UNIXSocket, Listener { + + override public init(path: URL) throws { + try super.init(path: path) + + do { + try bind(path) + } catch { + try close() + throw error + } + } + + private func bind(_ path: URL) throws { + var addr = sockaddr_un() + addr.sun_family = sa_family_t(AF_UNIX) + + let lengthOfPath = path.relativePath.withCString { Int(strlen($0)) } + + guard lengthOfPath < MemoryLayout.size(ofValue: addr.sun_path) else { + throw UNIXSocketError(kind: .pathLength, message: "Path too long!") + } + + _ = withUnsafeMutablePointer(to: &addr.sun_path.0) { ptr in + path.relativePath.withCString { + strncpy(ptr, $0, lengthOfPath) + } + } + + try withUnsafePointer(to: &addr) { + try $0.withMemoryRebound(to: sockaddr.self, capacity: 1) { + guard system_bind(fileNumber, $0, UInt32(MemoryLayout.stride)) != -1 else { + throw UNIXSocketError(kind: .bindError, errno: errno) + } + } + } + } + + private func listen(backlog: Int32) throws { + guard system_listen(fileNumber, backlog) != -1 else { + throw UNIXSocketError(kind: .listenError, errno: errno) + } + } + + /// Accepts a connection socket + public func accept() throws -> UNIXConnection { + let fileNumber = system_accept(self.fileNumber, nil, nil) + guard fileNumber != -1 else { + throw UNIXSocketError(kind: .acceptError, errno: errno) + } + + return UNIXConnection(fileNumber: fileNumber) + } +} diff --git a/Sources/UNIXSocket.swift b/Sources/UNIXSocket.swift new file mode 100644 index 0000000..8b2bf60 --- /dev/null +++ b/Sources/UNIXSocket.swift @@ -0,0 +1,61 @@ +import Foundation +#if os(Linux) +import Glibc +private let sock_stream = Int32(SOCK_STREAM.rawValue) +#else +import Darwin +private let sock_stream = SOCK_STREAM +#endif + +struct UNIXSocketError: Error { + enum ErrorKind: String { + case noSocket, creationError, pathLength, bindError, listenError, acceptError, connectError, unknownError + } + + let kind: ErrorKind + let message: String? + + var localizedDescription: String { + "UNIXSocketError of kind \(kind.rawValue)\(message != nil ? "\nmessage: \(message!)" : "")" + } + + init(kind: ErrorKind, message: String? = nil) { + self.kind = kind + self.message = message + } + + init(kind: ErrorKind, errno: Int32) { + let message = String(utf8String: strerror(errno)) + self.init(kind: kind, message: message) + } +} + +public class UNIXSocket: FileDescriptor { + public var fileNumber: FileNumber + + init(path: URL) throws { + guard let type = try? path.resourceValues(forKeys: [.fileResourceTypeKey]).fileResourceType, type == .socket else { + throw UNIXSocketError(kind: .noSocket) + } + + fileNumber = socket(AF_UNIX, sock_stream, 0) + guard fileNumber != -1 else { + throw UNIXSocketError(kind: .creationError, errno: errno) + } + } + + init(kind: Int32) throws { + fileNumber = socket(kind, sock_stream, 0) + guard fileNumber != -1 else { + throw UNIXSocketError(kind: .creationError, errno: errno) + } + } + + init(fileNumber: FileNumber) { + self.fileNumber = fileNumber + } + + deinit { + let _ = try? close() + } +} diff --git a/Sources/WritableFileDescriptor.swift b/Sources/WritableFileDescriptor.swift index d3165a9..31d38d7 100644 --- a/Sources/WritableFileDescriptor.swift +++ b/Sources/WritableFileDescriptor.swift @@ -1,3 +1,4 @@ +import Foundation #if os(Linux) import Glibc private let system_write = Glibc.write @@ -6,20 +7,24 @@ import Darwin private let system_write = Darwin.write #endif - -public protocol WritableFileDescriptor : FileDescriptor { -} - +public protocol WritableFileDescriptor : FileDescriptor {} extension WritableFileDescriptor { - /// Write attemps to write the given bytes to the file descriptor - public func write(_ bytes: [Byte]) throws -> Int { - let size = system_write(fileNumber, bytes, bytes.count) - - if size == -1 { - throw FileDescriptorError() + /// Write attemps to write the given bytes to the file descriptor + public func write(_ bytes: [Byte]) throws -> Int { + let size = system_write(fileNumber, bytes, bytes.count) + + guard size != -1 else { + throw FileDescriptorError(kind: .writeError, errno: errno) + } + + return size + } + + /// Write attemps to write the given data to the file descriptor + public func write(_ data: Data) throws -> Int { + let bytes = [Byte](data) + + return try write(bytes) } - - return size - } } diff --git a/Sources/select.swift b/Sources/select.swift index 7f54be0..7b92ed3 100644 --- a/Sources/select.swift +++ b/Sources/select.swift @@ -8,46 +8,45 @@ private let system_select = Darwin.select func filter(_ sockets: [T]?, _ set: inout fd_set) -> [T] { - return sockets?.filter { - fdIsSet($0.fileNumber, &set) - } ?? [] + return sockets?.filter { + fdIsSet($0.fileNumber, &set) + } ?? [] } public func select(reads: [R] = [], writes: [W] = [], errors: [E] = [], timeout: timeval? = nil) throws -> (reads: [R], writes: [W], errors: [E]) { - var readFDs = fd_set() - fdZero(&readFDs) - reads.forEach { fdSet($0.fileNumber, &readFDs) } - - var writeFDs = fd_set() - fdZero(&writeFDs) - writes.forEach { fdSet($0.fileNumber, &writeFDs) } - - var errorFDs = fd_set() - fdZero(&errorFDs) - errors.forEach { fdSet($0.fileNumber, &errorFDs) } - - let readFDNumbers = reads.map { $0.fileNumber } - let writeFDNumbers = writes.map { $0.fileNumber } - let errorFDNumbers = errors.map { $0.fileNumber } - let maxFD = (readFDNumbers + writeFDNumbers + errorFDNumbers).reduce(0, max) - let result: Int32 - if let timeout = timeout { - var timeout = timeout - result = system_select(maxFD + 1, &readFDs, &writeFDs, &errorFDs, &timeout) - } else { - result = system_select(maxFD + 1, &readFDs, &writeFDs, &errorFDs, nil) - } - - if result == 0 { - return ([], [], []) - } else if result > 0 { - return ( - filter(reads, &readFDs), - filter(writes, &writeFDs), - filter(errors, &errorFDs) - ) - } - - throw FileDescriptorError() + var readFDs = fd_set() + fdZero(&readFDs) + reads.forEach { fdSet($0.fileNumber, &readFDs) } + + var writeFDs = fd_set() + fdZero(&writeFDs) + writes.forEach { fdSet($0.fileNumber, &writeFDs) } + + var errorFDs = fd_set() + fdZero(&errorFDs) + errors.forEach { fdSet($0.fileNumber, &errorFDs) } + + let readFDNumbers = reads.map { $0.fileNumber } + let writeFDNumbers = writes.map { $0.fileNumber } + let errorFDNumbers = errors.map { $0.fileNumber } + let maxFD = (readFDNumbers + writeFDNumbers + errorFDNumbers).reduce(0, max) + let result: Int32 + if var timeout = timeout { + result = system_select(maxFD + 1, &readFDs, &writeFDs, &errorFDs, &timeout) + } else { + result = system_select(maxFD + 1, &readFDs, &writeFDs, &errorFDs, nil) + } + + if result == 0 { + return ([], [], []) + } else if result > 0 { + return ( + filter(reads, &readFDs), + filter(writes, &writeFDs), + filter(errors, &errorFDs) + ) + } + + throw FileDescriptorError(kind: .selectError, errno: errno) } diff --git a/Tests/fdTests/FileDescriptorSpec.swift b/Tests/fdTests/FileDescriptorSpec.swift index db91048..5c061f0 100644 --- a/Tests/fdTests/FileDescriptorSpec.swift +++ b/Tests/fdTests/FileDescriptorSpec.swift @@ -45,7 +45,7 @@ public func testFileDescriptor() { let (read, write) = try pipe() try expect(try write.write([1, 2, 3])) == 3 - let bytes = try read.read(3) + let bytes: [Byte] = try read.read(3) try expect(bytes.count) == 3 try expect(bytes[0]) == 1 try expect(bytes[1]) == 2 @@ -59,7 +59,7 @@ public func testFileDescriptor() { $0.it("errors while reading from an invalid file descriptor") { let descriptor = TestFileDescriptor(fileNumber: -1) - try expect { try descriptor.read(1) }.toThrow() + try expect { try descriptor.read(1) as [Byte] }.toThrow() } } } diff --git a/Tests/fdTests/UNIXListenerSpec.swift b/Tests/fdTests/UNIXListenerSpec.swift deleted file mode 100644 index bb5da8f..0000000 --- a/Tests/fdTests/UNIXListenerSpec.swift +++ /dev/null @@ -1,12 +0,0 @@ -import Spectre -import fd - - -public func testUNIXListener() { - describe("UNIXListener") { - $0.it("may be initialised with a path") { - let listener = try UNIXListener(path: "/tmp/fd-unixlistener-test") - try expect(listener.fileNumber) != -1 - } - } -} diff --git a/Tests/fdTests/UNIXServerSocketSpec.swift b/Tests/fdTests/UNIXServerSocketSpec.swift new file mode 100644 index 0000000..bcabfe8 --- /dev/null +++ b/Tests/fdTests/UNIXServerSocketSpec.swift @@ -0,0 +1,14 @@ +import Foundation +import Spectre +import fd + + +public func testUNIXServerSocket() { + describe("UNIXListener") { + $0.it("may be initialised with a path") { + let path = URL(string: "/tmp/fd-unixlistener-test")! + let listener = try UNIXServerSocket(path: path) + try expect(listener.fileNumber) != -1 + } + } +} diff --git a/Tests/fdTests/XCTest.swift b/Tests/fdTests/XCTest.swift index bb6f48a..fcebb36 100644 --- a/Tests/fdTests/XCTest.swift +++ b/Tests/fdTests/XCTest.swift @@ -8,6 +8,6 @@ class FDTests: XCTestCase { testTCPConnection() testTCPListener() testUNIXConnection() - testUNIXListener() + testUNIXServerSocket() } }