diff --git a/FlyingSocks/Sources/Socket.swift b/FlyingSocks/Sources/Socket.swift index a72ef79..df39b11 100644 --- a/FlyingSocks/Sources/Socket.swift +++ b/FlyingSocks/Sources/Socket.swift @@ -257,9 +257,12 @@ public struct Socket: Sendable, Hashable { private func read(into buffer: UnsafeMutablePointer, length: Int) throws -> Int { let count = Socket.read(file.rawValue, buffer, length) guard count > 0 else { - if errno == EWOULDBLOCK { + // count == 0 is EOF; errno is only valid after a -1 return. + if count == 0 { + throw SocketError.disconnected + } else if errno == EWOULDBLOCK { throw SocketError.blocked - } else if errnoSignalsDisconnected() || count == 0 { + } else if errnoSignalsDisconnected() { throw SocketError.disconnected } else { throw SocketError.makeFailed("Read") @@ -292,9 +295,12 @@ public struct Socket: Sendable, Hashable { Socket.recvfrom(file.rawValue, buffer, length, 0, $0, &size) } guard count > 0 else { - if errno == EWOULDBLOCK { + // count == 0 is EOF; errno is only valid after a -1 return. + if count == 0 { + throw SocketError.disconnected + } else if errno == EWOULDBLOCK { throw SocketError.blocked - } else if errnoSignalsDisconnected() || count == 0 { + } else if errnoSignalsDisconnected() { throw SocketError.disconnected } else { throw SocketError.makeFailed("RecvFrom") @@ -357,9 +363,12 @@ public struct Socket: Sendable, Hashable { } guard count > 0 else { - if errno == EWOULDBLOCK || errno == EAGAIN { + // count == 0 is EOF; errno is only valid after a -1 return. + if count == 0 { + throw SocketError.disconnected + } else if errno == EWOULDBLOCK || errno == EAGAIN { throw SocketError.blocked - } else if errnoSignalsDisconnected() || count == 0 { + } else if errnoSignalsDisconnected() { throw SocketError.disconnected } else { throw SocketError.makeFailed("RecvMsg") diff --git a/FlyingSocks/Sources/SocketPool+ePoll.swift b/FlyingSocks/Sources/SocketPool+ePoll.swift index 7034e84..1a134ec 100644 --- a/FlyingSocks/Sources/SocketPool+ePoll.swift +++ b/FlyingSocks/Sources/SocketPool+ePoll.swift @@ -31,6 +31,13 @@ #if canImport(CSystemLinux) import CSystemLinux +#if canImport(Glibc) +import Glibc +#elseif canImport(Musl) +import Musl +#elseif canImport(Android) +import Android +#endif public extension AsyncSocketPool where Self == SocketPool { static func ePoll(triggering: ePoll.TriggerMode = .edge, maxEvents limit: Int = 20, logger: some Logging = .disabled) -> SocketPool { @@ -147,6 +154,11 @@ public struct ePoll: EventQueue { var events = Array(repeating: epoll_event(), count: eventsLimit) let status = CSystemLinux.epoll_wait(file.rawValue, &events, Int32(eventsLimit), -1) guard status > 0 else { + // EINTR (signal) is not a failure: report no events so the caller + // polls again rather than tearing down the server. + if status == -1 && errno == EINTR { + return [] + } throw SocketError.makeFailed("epoll wait") }