{-# language BangPatterns #-} {-# language DuplicateRecordFields #-} {-# language PatternSynonyms #-} {-# language LambdaCase #-} {-# language NamedFieldPuns #-} module Network.Unexceptional ( accept_ ) where import Network.Socket (Socket,mkSocket,withFdSocket) import Foreign.C.Error (Errno) import GHC.Conc (threadWaitRead) import Foreign.C.Error.Pattern (pattern EWOULDBLOCK,pattern EAGAIN) import System.Posix.Types (Fd(Fd)) import qualified Linux.Socket as X -- | Accept a connection. See the documentation in @network@ for @accept@. -- -- Note: This may leak a file descriptor if an asynchronous exception is -- received while this function is running. accept_ :: Socket -> IO (Either Errno Socket) accept_ listing_sock = withFdSocket listing_sock $ \listing_fd -> do let acceptLoop = do threadWaitRead (Fd listing_fd) X.uninterruptibleAccept4_ (Fd listing_fd) (X.nonblocking <> X.closeOnExec) >>= \case Left e -> if e == EAGAIN || e == EWOULDBLOCK then acceptLoop else pure (Left e) Right (Fd fd) -> fmap Right (mkSocket fd) acceptLoop