packages feed

posix-api 0.7.1.0 → 0.7.2.0

raw patch · 22 files changed

+2255/−2569 lines, 22 filesdep −primitive-unlifteddep ~primitivesetup-changednew-uploaderPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependencies removed: primitive-unlifted

Dependency ranges changed: primitive

API changes (from Hackage documentation)

+ Posix.File: uninterruptibleReadMutableByteArray :: Fd -> MutableByteArray RealWorld -> Int -> CSize -> IO (Either Errno CSize)
+ Posix.Socket: socket :: Family -> Type -> Protocol -> IO (Either Errno Fd)
+ Posix.Socket: withSocket :: Family -> Type -> Protocol -> (Fd -> IO a) -> IO (Either Errno a)
- Posix.Types: newtype CNfds
+ Posix.Types: newtype () => CNfds

Files

CHANGELOG.md view
@@ -7,12 +7,19 @@  This project adheres to the [Haskell Package Versioning Policy](https://pvp.haskell.org/). -## [0.7.1.0] - 2023-??-??+## 0.7.2.0 -- 2024-02-28 +- Add `socket` as alias for `uninterruptibleSocket`.+- Add `withSocket`.+- Removed `UNLIFTEDARRAYFUNCTIONS` flag and support for GHC < 9.4.++## 0.7.1.0 -- 2023-10-03+ - Add `uninterruptibleOpenModeUntypedFlags`. - Add `Posix.Struct.AddressInfo.Poke`.+- Add `Posix.File.uninterruptibleReadMutableByteArray`. -## [0.7.0.0] - 2023-08-30+## 0.7.0.0 -- 2023-08-30  - For now, remove all of the functions that work on UnliftedArray. These   will be added back later once hackage starts using GHC 9.4. They are@@ -20,35 +27,35 @@   with the `UNLIFTEDARRAYFUNCTIONS` flag to get them back. - Add `uninterruptibleConnectPtr` for better compatibility with `network`. -## [0.6.1.0] - 2023-08-14+## 0.6.1.0 -- 2023-08-14  - Add `uninterruptibleWriteBytesCompletelyErrno` - Add `writeBytesCompletelyErrno` - Add `uninterruptibleAccept4_` -## [0.6.0.1] - 2023-07-13+## 0.6.0.1 -- 2023-07-13  - Fix mistake in header file that caused builds to fail -## [0.6.0.0] - 2023-07-13+## 0.6.0.0 -- 2023-07-13  - Use Int instead of CInt for all offsets into byte arrays -## [0.5.0.0] - 2023-07-13+## 0.5.0.0 -- 2023-07-13  - Move Linux.Systemd to systemd-api library to make docs build on hackage. -## [0.4.0.1] - 2023-06-27+## 0.4.0.1 -- 2023-06-27  - Build with GHC 9.4 -## [0.4.0.0] - 2022-12-08+## 0.4.0.0 -- 2022-12-08  - Add `writeMutableByteArray` - In the 0.3.5.0 release, the major version was supposed to be bumped.   This is being done now instead. -## [0.3.5.0] - 2021-07-02+## 0.3.5.0 -- 2021-07-02  - Breaking: Start using pattern synonyms for macros. - Add dedicated modules for peeking at structures.@@ -57,26 +64,26 @@ - Add `uninterruptibleSetSocketOption`. - Add socket options `SO_BINDTODEVICE` and `SO_REUSEADDR`. -## [0.3.4.0] - 2020-03-09+## 0.3.4.0 -- 2020-03-09  - Add `Posix.File` - Add lower bound for `hsc2hs` build tool -## [0.3.3.0] - 2019-12-18+## 0.3.3.0 -- 2019-12-18  - Support several POSIX message queue functions. - Support Linux systemd functions. -## [0.3.2.0] - 2019-07-21+## 0.3.2.0 -- 2019-07-21  - Add more functions. -## [0.3.1.0] - YYYY-MM-DD+## 0.3.1.0 -- YYYY-MM-DD  - Make the test suite build again. - Add `uninterruptibleSendByteArrays`. -## [0.1.0.0] - 2018-01-02+## 0.1.0.0 -- 2018-01-02 - Initial release. - Includes a ton of sockets API stuff. - Includes the get working directory function.
− Setup.hs
@@ -1,2 +0,0 @@-import Distribution.Simple-main = defaultMain
cbits/HaskellPosix.c view
@@ -21,7 +21,7 @@ #define MAX_BYTEARRAYS 64  // Generally, this library tries to avoid wrapping POSIX functions-// in an additional function. However, for some functions whose wrappers+// in an additional function. However, for some functions whose // unsafe FFI wrappers use unpinned ByteArray instead of Addr, the only // way to support providing an offset (without just copying the bytes // into pinned memory) is to use a wrapper.@@ -48,6 +48,9 @@ } ssize_t recv_offset(int socket, char *buffer, HsInt offset, size_t length, int flags) {   return recv(socket, (void*)(buffer + offset), length, flags);+}+ssize_t read_offset(int fd, char *buffer, HsInt offset, size_t length) {+  return read(fd, (void*)(buffer + offset), length); } ssize_t send_offset(int socket, const char *buffer, HsInt offset, size_t length, int flags) {   return send(socket, (const void*)(buffer + offset), length, flags);
include/HaskellPosix.h view
@@ -3,6 +3,7 @@ #include <stdint.h> #include "Rts.h" +ssize_t read_offset(int socket, char *buffer, HsInt offset, size_t length); ssize_t recv_offset(int socket, char *buffer, HsInt offset, size_t length, int flags); ssize_t send_offset(int socket, const char *buffer, HsInt offset, size_t length, int flags); @@ -19,4 +20,3 @@ int recvmmsg_sockaddr_discard (int sockfd , int *lens   , StgArrBytes **bufs // used for output   , unsigned int vlen , int flags);-
include/custom.h view
@@ -72,4 +72,3 @@   } else { \     hsc_printf ("BAD_BYTEARRAY_ALIGNMENT"); \   }-
posix-api.cabal view
@@ -1,7 +1,7 @@-cabal-version: 2.2-name: posix-api-version: 0.7.1.0-synopsis: posix bindings+cabal-version:      3.0+name:               posix-api+version:            0.7.2.0+synopsis:           posix bindings description:   This library provides a very thin wrapper around POSIX APIs. It can be   compiled on any operating system that implements the standard as specified@@ -10,19 +10,19 @@   differs in several areas:   .   * `ByteArray` and `Addr` are used pervasively. There is no use of-    `String` in this library.+  `String` in this library.   .   * Functions do not throw errors. This library uses `IO (Either Errno a)`-    in places where `unix` would use `IO a`.+  in places where `unix` would use `IO a`.   .   * The numeric types from `Foreign.C.Types` and `System.Posix.Types` are-    used in the type signatures of functions so that a haskell function's-    type signature matches its underlying POSIX equivalent exactly.+  used in the type signatures of functions so that a haskell function's+  type signature matches its underlying POSIX equivalent exactly.   .   * Flags are newtypes over `CInt` (or whatever integral type matches the-    posix specification) rather than enumerations. The data constructors-    are exported, making the types extensible for operating system that-    have additional flags.+  posix specification) rather than enumerations. The data constructors+  are exported, making the types extensible for operating system that+  have additional flags.   .   About a dozen other packages offers wrappers for some subset of the POSIX   specification are strewn across hackage. They include `regex-posix`,@@ -32,58 +32,62 @@   this package from some or all of these others:   .   * Scope. Although this library does not include all APIs specified by-    POSIX, it welcomes as many of them as anyone is willing to implement.+  POSIX, it welcomes as many of them as anyone is willing to implement.   .   * Monomorphization. Effectful functions in this library return their-    results in `IO` rather than using a type that involves `MonadIO`-    or `MonadBaseControl`.+  results in `IO` rather than using a type that involves `MonadIO`+  or `MonadBaseControl`.   .   * Typeclass avoidance. This library does not introduce new typeclasses.-    Overloading is eschewed in favor of providing multiple functions-    with distinct names.+  Overloading is eschewed in favor of providing multiple functions+  with distinct names.   .   * Minimality. Functions wrapping the POSIX APIs do little more than-    wrap the underlying functions. The major deviation here is that,-    when applicable, the wrappers allocate buffers are the underlying-    functions fill. This eschews C's characteristic buffer-passing-    in favor of the Haskell convention of allocating internally and returning.-    A more minor deviation is that for safe FFI calls, this library-    will perform additional work to ensure that only pinned byte arrays are-    handed over.+  wrap the underlying functions. The major deviation here is that,+  when applicable, the wrappers allocate buffers are the underlying+  functions fill. This eschews C's characteristic buffer-passing+  in favor of the Haskell convention of allocating internally and returning.+  A more minor deviation is that for safe FFI calls, this library+  will perform additional work to ensure that only pinned byte arrays are+  handed over.   .   Unlike `network`, this sockets API in this library does not integrate   sockets with GHC's event manager. This is geared   toward an audience that understands how to use `threadWaitRead`   and `threadWaitWrite` with unsafe FFI calls to avoid blocking   the runtime.-homepage: https://github.com/andrewthad/posix-api-license: BSD-3-Clause-license-file: LICENSE-author: Andrew Martin-maintainer: andrew.thaddeus@gmail.com-copyright: 2018 Andrew Martin-category: System-build-type: Simple++homepage:           https://github.com/byteverse/posix-api+bug-reports:        https://github.com/byteverse/posix-api/issues+license:            BSD-3-Clause+license-file:       LICENSE+author:             Andrew Martin+maintainer:         amartin@layer3com.com+copyright:          2018 Andrew Martin+category:           System+build-type:         Simple extra-source-files:-  README.md-  CHANGELOG.md   cbits/HaskellPosix.c-  include/HaskellPosix.h   include/custom.h+  include/HaskellPosix.h +extra-doc-files:+  CHANGELOG.md+  README.md++tested-with:        GHC ==9.4.8 || ==9.6.3 || ==9.8.1+ flag assertions-  manual: True-  description: Extra run-time invariant checking -  default: False+  manual:      True+  description: Extra run-time invariant checking+  default:     False --- This only exists to help get this library to build on hackage.--- Whenever hackage moves to GHC 9.4, remove this.-flag unliftedarrayfunctions-  manual: True-  description: Build and export functions using unlifted arrays-  default: False+common build-settings+  default-language: Haskell2010+  ghc-options:      -Wall -Wunused-packages  library+  import:             build-settings   exposed-modules:     Foreign.C.String.Managed     Linux.Epoll@@ -95,11 +99,13 @@     Posix.Poll     Posix.Select     Posix.Socket-    Posix.Types-    Posix.Struct.SocketAddressInternet.Peek     Posix.Struct.AddressInfo.Peek     Posix.Struct.AddressInfo.Poke+    Posix.Struct.SocketAddressInternet.Peek+    Posix.Types+   other-modules:+    Assertion     Linux.Epoll.Types     Linux.MessageQueue.Types     Linux.Socket.Types@@ -108,43 +114,48 @@     Posix.Poll.Types     Posix.Socket.Platform     Posix.Socket.Types-    Assertion+   build-depends:-    , base >=4.16.3 && <5-    , byte-order >= 0.1.2 && <0.2-    , byteslice >= 0.2.10 && <0.3-    , primitive >= 0.7 && <0.10-    , primitive-addr >= 0.1 && <0.2-    , primitive-offset >= 0.2 && <0.3-    , run-st >= 0.1.1 && <0.2-    , text-short >=0.1.5-  if flag(unliftedarrayfunctions)-    build-depends: primitive-unlifted >=2.1 && <2.2-  hs-source-dirs: src+    , base              >=4.16.3 && <5+    , byte-order        >=0.1.2  && <0.2+    , byteslice         >=0.2.10 && <0.3+    , primitive         >=0.9    && <0.10+    , primitive-addr    >=0.1    && <0.2+    , primitive-offset  >=0.2    && <0.3+    , run-st            >=0.1.1  && <0.2+    , text-short        >=0.1.5++  hs-source-dirs:     src+   if flag(assertions)     hs-source-dirs: src-assertions+   else     hs-source-dirs: src-noassertions+   if os(linux)     hs-source-dirs: src-linux-  default-language: Haskell2010-  ghc-options: -Wall -O2-  c-sources: cbits/HaskellPosix.c-  include-dirs: include-  includes: HaskellPosix.h-  build-tool-depends: hsc2hs:hsc2hs >= 0.68.5 +  ghc-options:        -O2+  c-sources:          cbits/HaskellPosix.c+  include-dirs:       include+  includes:           HaskellPosix.h+  build-tool-depends: hsc2hs:hsc2hs >=0.68.5+ test-suite test-  type: exitcode-stdio-1.0+  import:         build-settings+  type:           exitcode-stdio-1.0   hs-source-dirs: test-  main-is: Main.hs+  main-is:        Main.hs   build-depends:     , base     , posix-api+    , primitive    >=0.7     , tasty     , tasty-hunit-    , primitive >= 0.7-    , primitive-unlifted-  ghc-options: -Wall -O2 -threaded-  default-language: Haskell2010 +  ghc-options:    -threaded++source-repository head+  type:     git+  location: git://github.com/byteverse/posix-api.git
src-assertions/Assertion.hs view
@@ -1,5 +1,4 @@-{-# language MagicHash #-}-{-# language UnboxedTuples #-}+{-# LANGUAGE MagicHash #-}  module Assertion   ( assertByteArrayPinned@@ -7,30 +6,22 @@   , assertMutablePrimArrayPinned   ) where -import GHC.Exts (isTrue#)- import qualified Data.Primitive as PM-import qualified GHC.Exts as Exts  assertMutablePrimArrayPinned :: PM.MutablePrimArray s a -> PM.MutablePrimArray s a-assertMutablePrimArrayPinned x = if isMutablePrimArrayPinned x-  then x-  else error "assertMutablePrimArrayPinned"--assertMutableByteArrayPinned :: PM.MutablePrimArray s a -> PM.MutablePrimArray s a-assertMutableByteArrayPinned x = if isMutableByteArrayPinned x-  then x-  else error "assertMutableByteArrayPinned"--isMutablePrimArrayPinned :: PM.MutablePrimArray s a -> Bool-{-# inline isMutablePrimArrayPinned #-}-isMutablePrimArrayPinned (PM.MutablePrimArray marr#) = isTrue# (Exts.isMutableByteArrayPinned# marr#)+assertMutablePrimArrayPinned x =+  if PM.isMutablePrimArrayPinned x+    then x+    else error "assertMutablePrimArrayPinned" -isMutableByteArrayPinned :: PM.MutableByteArray s -> Bool-{-# inline isMutableByteArrayPinned #-}-isMutableByteArrayPinned (PM.MutableByteArray marr#) = isTrue# (Exts.isMutableByteArrayPinned# marr#)+assertMutableByteArrayPinned :: PM.MutableByteArray s -> PM.MutableByteArray s+assertMutableByteArrayPinned x =+  if PM.isMutableByteArrayPinned x+    then x+    else error "assertMutableByteArrayPinned"  assertByteArrayPinned :: PM.ByteArray -> PM.ByteArray-assertByteArrayPinned x = if PM.isByteArrayPinned x-  then x-  else error "assertByteArrayPinned"+assertByteArrayPinned x =+  if PM.isByteArrayPinned x+    then x+    else error "assertByteArrayPinned"
src-linux/Posix/Socket/Platform.hsc view
@@ -40,7 +40,7 @@ import qualified Data.Primitive.Addr as PMA import qualified Foreign.Storable as FS --- | The size of a serialized internet socket address.  +-- | The size of a serialized internet socket address. sizeofSocketAddressInternet :: CInt sizeofSocketAddressInternet = #{size struct sockaddr_in} @@ -115,7 +115,7 @@ --   error code. encodeSocketAddressUnix :: SocketAddressUnix -> SocketAddress encodeSocketAddressUnix (SocketAddressUnix !name) =-  SocketAddress $ runByteArrayST $ unboxByteArrayST $ do +  SocketAddress $ runByteArrayST $ unboxByteArrayST $ do     -- On linux, sun_path always has exactly 108 bytes. It is a null-terminated     -- string, so we initialize the byte array to zeroes to ensure this     -- happens.@@ -142,4 +142,3 @@ -- data constructor allocation. runByteArrayST :: (State## RealWorld -> (## State## RealWorld, ByteArray## ##)) -> ByteArray runByteArrayST st_rep = case runRW## st_rep of (## _, a ##) -> ByteArray a-
src/Foreign/C/String/Managed.hs view
@@ -1,14 +1,14 @@-{-# language BangPatterns #-}-{-# language DerivingStrategies #-}-{-# language GeneralizedNewtypeDeriving #-}-{-# language MagicHash #-}-{-# language MultiWayIf #-}-{-# language TypeApplications #-}-{-# language ScopedTypeVariables #-}-{-# language UnboxedTuples #-}+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE DerivingStrategies #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE MagicHash #-}+{-# LANGUAGE MultiWayIf #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE UnboxedTuples #-}  module Foreign.C.String.Managed-  ( ManagedCString(..)+  ( ManagedCString (..)   , terminated   , terminatedU   , unterminated@@ -23,25 +23,24 @@  import Control.Monad.ST (ST) import Control.Monad.ST.Run (runByteArrayST)-import Data.Bytes.Types (Bytes(Bytes))+import Data.Bytes.Types (Bytes (Bytes)) import Data.Char (ord)-import Data.Primitive (ByteArray(..),MutableByteArray)+import Data.Primitive (ByteArray (..), MutableByteArray) import Data.Text.Short (ShortText) import Data.Word (Word8) import Foreign.C.String (CString) import Foreign.Ptr (castPtr)-import GHC.Exts (Int(I#),Char(C#),ByteArray#,chr#,touch#)-import GHC.IO (IO(IO))+import GHC.Exts (ByteArray#, Char (C#), Int (I#), chr#, touch#)+import GHC.IO (IO (IO))  import qualified Data.Bytes as Bytes import qualified Data.Bytes.Text.Utf8 as Utf8 import qualified Data.Primitive as PM-import qualified Data.Text.Short as TS import qualified GHC.Exts as Exts  -- | An unsliced byte sequence with @NUL@ as the final byte. newtype ManagedCString = ManagedCString ByteArray-  deriving newtype Eq+  deriving newtype (Eq)  instance Semigroup ManagedCString where   ManagedCString a <> ManagedCString b = ManagedCString $ runByteArrayST $ do@@ -62,14 +61,18 @@   fromString = fromLatinString  instance Show ManagedCString where-  showsPrec _ (ManagedCString arr) s0 = PM.foldrByteArray-    ( \(w :: Word8) s ->-      if | w == 0 -> s-         | w < 32 -> '?' : s-         | w > 126 -> '?' : s-         | otherwise -> case fromIntegral @Word8 @Int w of-             I# i -> C# (chr# i) : s-    ) s0 arr+  showsPrec _ (ManagedCString arr) s0 =+    PM.foldrByteArray+      ( \(w :: Word8) s ->+          if+            | w == 0 -> s+            | w < 32 -> '?' : s+            | w > 126 -> '?' : s+            | otherwise -> case fromIntegral @Word8 @Int w of+                I# i -> C# (chr# i) : s+      )+      s0+      arr  terminatedU :: ManagedCString -> ByteArray terminatedU (ManagedCString x) = x@@ -100,13 +103,14 @@   PM.unsafeFreezeByteArray dst  pin :: ManagedCString -> ManagedCString-pin (ManagedCString x) = if PM.isByteArrayPinned x-  then ManagedCString x-  else ManagedCString $ runByteArrayST $ do-    let len = PM.sizeofByteArray x-    dst <- PM.newPinnedByteArray len-    PM.copyByteArray dst 0 x 0 len-    PM.unsafeFreezeByteArray dst+pin (ManagedCString x) =+  if PM.isByteArrayPinned x+    then ManagedCString x+    else ManagedCString $ runByteArrayST $ do+      let len = PM.sizeofByteArray x+      dst <- PM.newPinnedByteArray len+      PM.copyByteArray dst 0 x 0 len+      PM.unsafeFreezeByteArray dst  touch :: ManagedCString -> IO () touch (ManagedCString (ByteArray x)) = touchByteArray# x@@ -114,32 +118,35 @@ touchByteArray# :: ByteArray# -> IO () touchByteArray# x = IO $ \s -> case touch# x s of s' -> (# s', () #) --- | Convert a 'String' consisting of only characters representable--- by ISO-8859-1. These are encoded with ISO-8859-1. Any character--- with a codepoint above @U+00FF@ is replaced by an unspecified byte.+{- | Convert a 'String' consisting of only characters representable+by ISO-8859-1. These are encoded with ISO-8859-1. Any character+with a codepoint above @U+00FF@ is replaced by an unspecified byte.+-} fromLatinString :: String -> ManagedCString-{-# noinline fromLatinString #-}+{-# NOINLINE fromLatinString #-} fromLatinString str = ManagedCString $ runByteArrayST $ do   let lenPred0 = 63   dst0 <- PM.newByteArray (lenPred0 + 1)   go str dst0 0 lenPred0-  where+ where   go :: forall s. String -> MutableByteArray s -> Int -> Int -> ST s ByteArray   go [] !dst !ix !_ = do     PM.writeByteArray dst ix (0 :: Word8)     PM.resizeMutableByteArray dst (ix + 1) >>= PM.unsafeFreezeByteArray-  go (c:cs) !dst !ix !lenPred = if ix < lenPred-    then do-      PM.writeByteArray dst ix (fromIntegral @Int @Word8 (ord c))-      go cs dst (ix + 1) lenPred-    else do-      let nextLenPred = lenPred * 2-      dst' <- PM.newByteArray (nextLenPred + 1)-      PM.copyMutableByteArray dst' 0 dst 0 ix-      PM.writeByteArray dst' ix (fromIntegral @Int @Word8 (ord c))-      go cs dst' (ix + 1) nextLenPred+  go (c : cs) !dst !ix !lenPred =+    if ix < lenPred+      then do+        PM.writeByteArray dst ix (fromIntegral @Int @Word8 (ord c))+        go cs dst (ix + 1) lenPred+      else do+        let nextLenPred = lenPred * 2+        dst' <- PM.newByteArray (nextLenPred + 1)+        PM.copyMutableByteArray dst' 0 dst 0 ix+        PM.writeByteArray dst' ix (fromIntegral @Int @Word8 (ord c))+        go cs dst' (ix + 1) nextLenPred --- | Get a pointer to the payload of the managed C string. The behavior is--- undefined if the argument is not pinned.+{- | Get a pointer to the payload of the managed C string. The behavior is+undefined if the argument is not pinned.+-} contents :: ManagedCString -> CString contents (ManagedCString x) = castPtr (PM.byteArrayContents x)
src/Linux/Epoll.hs view
@@ -1,30 +1,34 @@-{-# language BangPatterns #-}-{-# language DataKinds #-}-{-# language GADTSyntax #-}-{-# language KindSignatures #-}-{-# language MagicHash #-}-{-# language UnliftedFFITypes #-}-{-# language NamedFieldPuns #-}-{-# language UnboxedTuples #-}+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE GADTSyntax #-}+{-# LANGUAGE KindSignatures #-}+{-# LANGUAGE MagicHash #-}+{-# LANGUAGE UnliftedFFITypes #-}  module Linux.Epoll   ( -- * Functions+     -- ** Create     uninterruptibleCreate   , uninterruptibleCreate1+     -- ** Wait   , waitMutablePrimArray   , uninterruptibleWaitMutablePrimArray+     -- ** Control   , uninterruptibleControlMutablePrimArray+     -- * Types-  , EpollFlags(..)-  , ControlOperation(..)-  , Events(..)-  , Event(..)-  , Exchange(..)+  , EpollFlags (..)+  , ControlOperation (..)+  , Events (..)+  , Event (..)+  , Exchange (..)+     -- * Classes   , PrimEpollData+     -- * Constants   , T.closeOnExec   , T.add@@ -37,9 +41,11 @@   , T.readHangup   , T.error   , T.edgeTriggered+     -- * Events Combinators   , T.containsAnyEvents   , T.containsAllEvents+     -- * Marshalling   , T.sizeofEvent   , T.peekEventEvents@@ -48,21 +54,17 @@   , T.peekEventDataU32   , T.peekEventDataU64   , T.pokeEventDataU64-  -- , T.readEventDataU64-  -- , T.writeEventDataU64-  -- , T.writeEventEvents   ) where  import Prelude hiding (error)  import Assertion (assertMutablePrimArrayPinned)-import Data.Primitive (MutablePrimArray(..))-import Foreign.C.Error (Errno,getErrno)-import Foreign.C.Types (CInt(..))-import GHC.Exts (RealWorld,MutableByteArray#)-import Linux.Epoll.Types (EpollFlags(..),ControlOperation(..),Events(..),Exchange(..))-import Linux.Epoll.Types (Event(..),PrimEpollData(..))-import System.Posix.Types (Fd(..))+import Data.Primitive (MutablePrimArray (..))+import Foreign.C.Error (Errno, getErrno)+import Foreign.C.Types (CInt (..))+import GHC.Exts (MutableByteArray#, RealWorld)+import Linux.Epoll.Types (ControlOperation (..), EpollFlags (..), Event (..), Events (..), Exchange (..), PrimEpollData (..))+import System.Posix.Types (Fd (..))  import qualified Linux.Epoll.Types as T @@ -93,81 +95,99 @@ --   PM.writeByteArray arr (ix * 3 + 2) (word64ToWord32 payload)  uninterruptibleCreate ::-     CInt -- ^ Size, ignored since Linux 2.6.8-  -> IO (Either Errno Fd)-{-# inline uninterruptibleCreate #-}+  -- | Size, ignored since Linux 2.6.8+  CInt ->+  IO (Either Errno Fd)+{-# INLINE uninterruptibleCreate #-} uninterruptibleCreate !sz = c_epoll_create sz >>= errorsFromFd  uninterruptibleCreate1 ::-     EpollFlags -- ^ Flags-  -> IO (Either Errno Fd)-{-# inline uninterruptibleCreate1 #-}+  -- | Flags+  EpollFlags ->+  IO (Either Errno Fd)+{-# INLINE uninterruptibleCreate1 #-} uninterruptibleCreate1 !flags =   c_epoll_create1 flags >>= errorsFromFd --- | Wait for an I/O event on an epoll file descriptor. The---   <https://linux.die.net/man/2/epoll_wait Linux man page>---   includes more details. The @timeout@ argument is omitted---   since it is nonsense to choose anything other than 0 when---   using the unsafe FFI.+{- | Wait for an I/O event on an epoll file descriptor. The+  <https://linux.die.net/man/2/epoll_wait Linux man page>+  includes more details. The @timeout@ argument is omitted+  since it is nonsense to choose anything other than 0 when+  using the unsafe FFI.+-} uninterruptibleWaitMutablePrimArray ::-     Fd -- ^ EPoll file descriptor-  -> MutablePrimArray RealWorld (Event 'Response a) -- ^ Event buffer-  -> CInt -- ^ Maximum events-  -> IO (Either Errno CInt) -- ^ Number of events received-{-# inline uninterruptibleWaitMutablePrimArray #-}+  -- | EPoll file descriptor+  Fd ->+  -- | Event buffer+  MutablePrimArray RealWorld (Event 'Response a) ->+  -- | Maximum events+  CInt ->+  -- | Number of events received+  IO (Either Errno CInt)+{-# INLINE uninterruptibleWaitMutablePrimArray #-} uninterruptibleWaitMutablePrimArray !epfd (MutablePrimArray evs) !maxEvents =   c_epoll_wait_unsafe epfd evs maxEvents 0 >>= errorsFromInt --- | Wait for an I/O event on an epoll file descriptor. The---   <https://linux.die.net/man/2/epoll_wait Linux man page>---   includes more details. The event buffer must be a pinned---   byte array.+{- | Wait for an I/O event on an epoll file descriptor. The+  <https://linux.die.net/man/2/epoll_wait Linux man page>+  includes more details. The event buffer must be a pinned+  byte array.+-} waitMutablePrimArray ::-     Fd -- ^ EPoll file descriptor-  -> MutablePrimArray RealWorld (Event 'Response a) -- ^ Event buffer, must be pinned-  -> CInt -- ^ Maximum events-  -> CInt -- ^ Timeout in milliseconds, use @-1@ to block forever.-  -> IO (Either Errno CInt) -- ^ Number of events received-{-# inline waitMutablePrimArray #-}+  -- | EPoll file descriptor+  Fd ->+  -- | Event buffer, must be pinned+  MutablePrimArray RealWorld (Event 'Response a) ->+  -- | Maximum events+  CInt ->+  -- | Timeout in milliseconds, use @-1@ to block forever.+  CInt ->+  -- | Number of events received+  IO (Either Errno CInt)+{-# INLINE waitMutablePrimArray #-} waitMutablePrimArray !epfd !evs !maxEvents !timeout =   let !(MutablePrimArray evs#) = assertMutablePrimArrayPinned evs    in c_epoll_wait_safe epfd evs# maxEvents timeout >>= errorsFromInt --- | Add, modify, or remove entries in the interest list of the---   epoll instance referred to by the file descriptor @epfd@.---   <https://linux.die.net/man/2/epoll_ctl Linux man page>---   includes more details.+{- | Add, modify, or remove entries in the interest list of the+  epoll instance referred to by the file descriptor @epfd@.+  <https://linux.die.net/man/2/epoll_ctl Linux man page>+  includes more details.+-} uninterruptibleControlMutablePrimArray ::-     Fd -- ^ EPoll file descriptor (@epfd@)-  -> ControlOperation-     -- ^ Operation: @EPOLL_CTL_ADD@, @EPOLL_CTL_MOD@, or @EPOLL_CTL_DEL@-  -> Fd -- ^ File descriptor whose registration will be affected-  -> MutablePrimArray RealWorld (Event 'Request a)-     -- ^ A single event. This is read from, not written to.-  -> IO (Either Errno ())-{-# inline uninterruptibleControlMutablePrimArray #-}+  -- | EPoll file descriptor (@epfd@)+  Fd ->+  -- | Operation: @EPOLL_CTL_ADD@, @EPOLL_CTL_MOD@, or @EPOLL_CTL_DEL@+  ControlOperation ->+  -- | File descriptor whose registration will be affected+  Fd ->+  -- | A single event. This is read from, not written to.+  MutablePrimArray RealWorld (Event 'Request a) ->+  IO (Either Errno ())+{-# INLINE uninterruptibleControlMutablePrimArray #-} uninterruptibleControlMutablePrimArray !epfd !op !fd (MutablePrimArray ev) =   c_epoll_ctl_unsafe epfd op fd ev >>= errorsFromInt_  errorsFromFd :: Fd -> IO (Either Errno Fd)-{-# inline errorsFromFd #-}-errorsFromFd r = if r > (-1)-  then pure (Right r)-  else fmap Left getErrno+{-# INLINE errorsFromFd #-}+errorsFromFd r =+  if r > (-1)+    then pure (Right r)+    else fmap Left getErrno  errorsFromInt :: CInt -> IO (Either Errno CInt)-{-# inline errorsFromInt #-}-errorsFromInt r = if r > (-1)-  then pure (Right r)-  else fmap Left getErrno+{-# INLINE errorsFromInt #-}+errorsFromInt r =+  if r > (-1)+    then pure (Right r)+    else fmap Left getErrno  -- Sometimes, functions that return an int use zero to indicate -- success and negative one to indicate failure without including -- additional information in the value. errorsFromInt_ :: CInt -> IO (Either Errno ())-{-# inline errorsFromInt_ #-}-errorsFromInt_ r = if r == 0-  then pure (Right ())-  else fmap Left getErrno-+{-# INLINE errorsFromInt_ #-}+errorsFromInt_ r =+  if r == 0+    then pure (Right ())+    else fmap Left getErrno
src/Linux/Epoll/Types.hsc view
@@ -11,7 +11,7 @@ {-# language PolyKinds #-} {-# language ScopedTypeVariables #-} {-# language TypeApplications #-}-{-# language TypeInType #-}+{-# language DataKinds #-} {-# language UnboxedTuples #-}  -- This is needed because hsc2hs does not currently handle ticked@@ -334,30 +334,3 @@  unI :: Int -> Int## unI (I## i) = i---- -- | Read @data.u64@ from @struct epoll_event@.--- readEventDataU64 ::---      MutableByteArray RealWorld---   -> Int -- ^ Index. Elements are @struct epoll_event@.---   -> IO Word64--- readEventDataU64 !arr !ix = do---   -- On 64-bit platforms, Linux bitpacks this structure, causing the---   -- data (a 64-bit word) to be misaligned. Consequently, we must---   -- hardcode the assumed offsets to perform only aligned accesses.---   -- The behavior is deterministic across platforms of different---   -- endianness only if the only use of this function is paired with---   -- writeEventDataU64.---   (a :: Word32) <- PM.readByteArray arr (ix * 3 + 1)---   (b :: Word32) <- PM.readByteArray arr (ix * 3 + 2)---   pure (unsafeShiftL (word32ToWord64 a) 32 .|. word32ToWord64 b)--- --- -- | Write @data.u64@ from @struct epoll_event@.--- writeEventDataU64 ::---      MutableByteArray RealWorld---   -> Int -- ^ Index. Element are @struct epoll_event@.---   -> Word64 -- ^ Data---   -> IO ()--- writeEventDataU64 !arr !ix !payload = do---   -- See the comments on readEventDataU64---   PM.writeByteArray arr (ix * 3 + 1) (word64ToWord32 (unsafeShiftR payload 32))---   PM.writeByteArray arr (ix * 3 + 2) (word64ToWord32 payload)
src/Linux/Socket.hs view
@@ -1,40 +1,40 @@-{-# language BangPatterns #-}-{-# language CPP #-}-{-# language DataKinds #-}-{-# language MagicHash #-}-{-# language ScopedTypeVariables #-}-{-# language UnboxedTuples #-}-{-# language UnliftedFFITypes #-}+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE CPP #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE MagicHash #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE UnliftedFFITypes #-}  module Linux.Socket   ( -- * Functions     uninterruptibleAccept4   , uninterruptibleAccept4_-#if defined(UNLIFTEDARRAYFUNCTIONS)-  , uninterruptibleReceiveMultipleMessageA-  , uninterruptibleReceiveMultipleMessageB-  , uninterruptibleReceiveMultipleMessageC-  , uninterruptibleReceiveMultipleMessageD-#endif+     -- * Types-  , SocketFlags(..)+  , SocketFlags (..)+     -- * Option Names   , LST.headerInclude+     -- * Message Flags   , LST.dontWait   , LST.truncate   , LST.controlTruncate+     -- * Socket Flags   , LST.closeOnExec   , LST.nonblocking+     -- * Twiddle   , applySocketFlags+     -- * UDP Header   , LST.sizeofUdpHeader   , LST.pokeUdpHeaderSourcePort   , LST.pokeUdpHeaderDestinationPort   , LST.pokeUdpHeaderLength   , LST.pokeUdpHeaderChecksum+     -- * IPv4 Header   , LST.sizeofIpHeader   , LST.pokeIpHeaderVersionIhl@@ -51,333 +51,74 @@  import Prelude hiding (truncate) -import Control.Monad (when) import Data.Bits ((.|.))-import Data.Primitive (MutableByteArray(..),ByteArray(..),MutablePrimArray(..))-import Data.Primitive.Addr (Addr(..),plusAddr,nullAddr)-#if defined(UNLIFTEDARRAYFUNCTIONS)-import Data.Primitive.Unlifted.Array (MutableUnliftedArray,UnliftedArray)-import Data.Primitive.Unlifted.Array (MutableUnliftedArray_(MutableUnliftedArray))-import Data.Primitive.Unlifted.Array.Primops (MutableUnliftedArray#(MutableUnliftedArray#))-#endif+import Data.Primitive (MutableByteArray (..)) import Data.Void (Void)-import Data.Word (Word8)-import Foreign.C.Error (Errno,getErrno)-import Foreign.C.Types (CInt(..),CSize(..),CUInt(..))+import Foreign.C.Error (Errno, getErrno)+import Foreign.C.Types (CInt (..)) import Foreign.Ptr (nullPtr)-import GHC.Exts (Ptr(..),RealWorld,MutableArray#,MutableByteArray#,Addr#,Int(I#))-import GHC.Exts (shrinkMutableByteArray#,touch#,nullAddr#)-import GHC.IO (IO(..))-import Linux.Socket.Types (SocketFlags(..))-import Posix.Socket (Type(..),MessageFlags(..),Message(Receive),SocketAddress(..))-import System.Posix.Types (Fd(..),CSsize(..))+import GHC.Exts (Int (I#), MutableByteArray#, Ptr (..), RealWorld, shrinkMutableByteArray#)+import Linux.Socket.Types (SocketFlags (..))+import Posix.Socket (SocketAddress (..), Type (..))+import System.Posix.Types (Fd (..))  import qualified Control.Monad.Primitive as PM import qualified Data.Primitive as PM-#if defined(UNLIFTEDARRAYFUNCTIONS)-import qualified Data.Primitive.Unlifted.Array as PM-#endif import qualified Linux.Socket.Types as LST-import qualified Posix.Socket as S -foreign import ccall unsafe "sys/socket.h recvmmsg"-  c_unsafe_addr_recvmmsg :: Fd-                         -> Addr# -- This addr is an array of msghdr-                         -> CUInt -- Length of msghdr array-                         -> MessageFlags 'Receive-                         -> Addr# -- Timeout-                         -> IO CSsize- foreign import ccall unsafe "sys/socket.h accept4"-  c_unsafe_accept4 :: Fd-                   -> MutableByteArray# RealWorld -- SocketAddress-                   -> MutableByteArray# RealWorld -- Ptr CInt-                   -> SocketFlags-                   -> IO Fd+  c_unsafe_accept4 ::+    Fd ->+    MutableByteArray# RealWorld -> -- SocketAddress+    MutableByteArray# RealWorld -> -- Ptr CInt+    SocketFlags ->+    IO Fd  -- Variant of c_unsafe_ptr_accept4 that uses Ptr instead of MutableByteArray. -- Currently, we expect that the two pointers are set to NULL. -- This is only used internally. foreign import ccall unsafe "sys/socket.h accept4"   c_unsafe_ptr_accept4 ::-        Fd-     -> Ptr Void -- SocketAddress-     -> Ptr Void -- Ptr CInt-     -> SocketFlags-     -> IO Fd+    Fd ->+    Ptr Void -> -- SocketAddress+    Ptr Void -> -- Ptr CInt+    SocketFlags ->+    IO Fd -#if defined(UNLIFTEDARRAYFUNCTIONS)-foreign import ccall unsafe "HaskellPosix.h recvmmsg_sockaddr_in"-  c_unsafe_recvmmsg_sockaddr_in ::-       Fd-    -> MutableByteArray# RealWorld -- lengths-    -> MutableByteArray# RealWorld -- sockaddrs-    -> MutableArray# RealWorld (MutableByteArray# RealWorld) -- buffers-    -> CUInt -- Length of msghdr array-    -> MessageFlags 'Receive-    -> IO CInt+{- | Linux extends the @type@ argument of+  <http://man7.org/linux/man-pages/man2/socket.2.html socket> to allow+  setting two socket flags on socket creation: @SOCK_CLOEXEC@ and+  @SOCK_NONBLOCK@. It is advisable to set @SOCK_CLOEXEC@ on when+  opening a socket on linux. For example, we may open a TCP Internet+  socket with: -foreign import ccall unsafe "HaskellPosix.h recvmmsg_sockaddr_discard"-  c_unsafe_recvmmsg_sockaddr_discard ::-       Fd-    -> MutableByteArray# RealWorld -- lengths-    -> MutableArray# RealWorld (MutableByteArray# RealWorld) -- buffers-    -> CUInt -- Length of msghdr array-    -> MessageFlags 'Receive-    -> IO CInt-#endif+  > uninterruptibleSocket internet (applySocketFlags closeOnExec stream) defaultProtocol --- | Linux extends the @type@ argument of---   <http://man7.org/linux/man-pages/man2/socket.2.html socket> to allow---   setting two socket flags on socket creation: @SOCK_CLOEXEC@ and---   @SOCK_NONBLOCK@. It is advisable to set @SOCK_CLOEXEC@ on when---   opening a socket on linux. For example, we may open a TCP Internet---   socket with:------   > uninterruptibleSocket internet (applySocketFlags closeOnExec stream) defaultProtocol------   To additionally open the socket in nonblocking mode---   (e.g. with @SOCK_NONBLOCK@):------   > uninterruptibleSocket internet (applySocketFlags (closeOnExec <> nonblocking) stream) defaultProtocol---   +  To additionally open the socket in nonblocking mode+  (e.g. with @SOCK_NONBLOCK@):++  > uninterruptibleSocket internet (applySocketFlags (closeOnExec <> nonblocking) stream) defaultProtocol+-} applySocketFlags :: SocketFlags -> Type -> Type applySocketFlags (SocketFlags s) (Type t) = Type (s .|. t) -#if defined(UNLIFTEDARRAYFUNCTIONS)--- | Receive multiple messages. This does not provide the socket---   addresses or the control messages. It does not use any of the---   input-scattering that @recvmmsg@ offers, meaning that a single---   datagram is never split across noncontiguous memory. It supplies---   @NULL@ for the timeout argument. All of the messages must have the---   same maximum size. All resulting byte arrays have been explicitly---   pinned. In addition to bytearrays corresponding to each datagram,---   this also provides the maximum @msg_len@ that @recvmmsg@ wrote---   back out. This is provided so that users of @MSG_TRUNC@ can detect---   when bytes were dropped from the end of a message (although it does---   let the user figure out which message had bytes dropped).-uninterruptibleReceiveMultipleMessageA ::-     Fd -- ^ Socket-  -> CSize -- ^ Maximum bytes per message-  -> CUInt -- ^ Maximum number of messages-  -> MessageFlags 'Receive -- ^ Flags-  -> IO (Either Errno (CUInt,UnliftedArray ByteArray))-uninterruptibleReceiveMultipleMessageA !s !msgSize !msgCount !flags = do-  placeholder <- PM.newByteArray 0-  bufs <- PM.newUnliftedArray (cuintToInt msgCount) placeholder-  mmsghdrsBuf <- PM.newPinnedByteArray (cuintToInt msgCount * cintToInt LST.sizeofMultipleMessageHeader)-  iovecsBuf <- PM.newPinnedByteArray (cuintToInt msgCount * cintToInt S.sizeofIOVector)-  let !mmsghdrsAddr@(Addr mmsghdrsAddr#) = ptrToAddr (PM.mutableByteArrayContents mmsghdrsBuf)-  let iovecsAddr = ptrToAddr (PM.mutableByteArrayContents iovecsBuf)-  initializeMultipleMessageHeadersWithoutSockAddr bufs iovecsAddr mmsghdrsAddr msgSize msgCount-  r <- c_unsafe_addr_recvmmsg s mmsghdrsAddr# msgCount flags nullAddr#-  if r > (-1)-    then do-      (_,maxMsgSz,frozenBufs) <- shrinkAndFreezeMessages msgSize 0 (cssizeToInt r) bufs mmsghdrsAddr-      touchMutableUnliftedArray bufs-      touchMutableByteArray iovecsBuf-      touchMutableByteArray mmsghdrsBuf-      pure (Right (maxMsgSz,frozenBufs))-    else do-      touchMutableUnliftedArray bufs-      touchMutableByteArray iovecsBuf-      touchMutableByteArray mmsghdrsBuf-      fmap Left getErrno---- | Receive multiple messages. This is similar to--- @uninterruptibleReceiveMultipleMessageA@. However, it also--- provides the @sockaddr@s of the remote endpoints. These are--- written in contiguous memory to a bytearray of length--- @max_num_msgs * expected_sockaddr_sz@. The @sockaddr@s must--- all be expected to be of the same length. This function--- provides a @sockaddr@ size check that is non-zero when any--- @sockaddr@ had a length other than the expected length.--- This can be used to detect if the @sockaddr@ array has one or--- more corrupt @sockaddr@s in it. All byte arrays returned by--- this function are pinned.------ The values in the returned tuple are:------ * Error-checking number for @sockaddr@ size. Non-zero indicates---   that at least one @sockaddr@ required a number of bytes other---   than the expected number.--- * Pinned bytearray with all of the @sockaddr@s in it as a---   array of structures.--- * The size of the largest message received. If @MSG_TRUNC@ is used---   this lets the caller know if one or more messages were truncated.--- * The message data of each message.------ The @sockaddr@s bytearray and the unlifted array of messages are--- guaranteed to have the same number of elements. -uninterruptibleReceiveMultipleMessageB ::-     Fd -- ^ Socket-  -> CInt -- ^ Expected @sockaddr@ size-  -> CSize -- ^ Maximum bytes per message-  -> CUInt -- ^ Maximum number of messages-  -> MessageFlags 'Receive -- ^ Flags-  -> IO (Either Errno (CInt,ByteArray,CUInt,UnliftedArray ByteArray))-uninterruptibleReceiveMultipleMessageB !s !expSockAddrSize !msgSize !msgCount !flags = do-  placeholder <- PM.newByteArray 0-  bufs <- PM.newUnliftedArray (cuintToInt msgCount) placeholder-  mmsghdrsBuf <- PM.newPinnedByteArray (cuintToInt msgCount * cintToInt LST.sizeofMultipleMessageHeader)-  iovecsBuf <- PM.newPinnedByteArray (cuintToInt msgCount * cintToInt S.sizeofIOVector)-  sockaddrsBuf <- PM.newPinnedByteArray (cuintToInt msgCount * cintToInt expSockAddrSize)-  -- Linux does not require zeroing out sockaddr_in before using it,-  -- so we leave sockaddrsBuf alone after initialization.-  let sockaddrsAddr = ptrToAddr (PM.mutableByteArrayContents sockaddrsBuf)-  let !mmsghdrsAddr@(Addr mmsghdrsAddr#) = ptrToAddr (PM.mutableByteArrayContents mmsghdrsBuf)-  let iovecsAddr = ptrToAddr (PM.mutableByteArrayContents iovecsBuf)-  initializeMultipleMessageHeadersWithSockAddr bufs iovecsAddr mmsghdrsAddr sockaddrsAddr expSockAddrSize msgSize msgCount-  r <- c_unsafe_addr_recvmmsg s mmsghdrsAddr# msgCount flags nullAddr#-  if r > (-1)-    then do-      (validation,maxMsgSz,frozenBufs) <- shrinkAndFreezeMessages msgSize expSockAddrSize (cssizeToInt r) bufs mmsghdrsAddr-      shrinkMutableByteArray sockaddrsBuf (cssizeToInt r * cintToInt expSockAddrSize)-      sockaddrs <- PM.unsafeFreezeByteArray sockaddrsBuf-      touchMutableByteArray iovecsBuf-      touchMutableByteArray mmsghdrsBuf-      touchMutableByteArray sockaddrsBuf-      pure (Right (validation,sockaddrs,maxMsgSz,frozenBufs))-    else do-      touchMutableUnliftedArray bufs-      touchMutableByteArray iovecsBuf-      touchMutableByteArray mmsghdrsBuf-      touchMutableByteArray sockaddrsBuf-      fmap Left getErrno---- | All three buffer arguments need to have the same length (in elements, not bytes).-uninterruptibleReceiveMultipleMessageC ::-     Fd -- ^ Socket-  -> MutablePrimArray RealWorld CInt -- ^ Buffer for payload lengths-  -> MutablePrimArray RealWorld S.SocketAddressInternet -- ^ Buffer for @sockaddr_in@s-  -> MutableUnliftedArray RealWorld (MutableByteArray RealWorld) -- ^ Buffers for payloads-  -> CUInt -- ^ Maximum number of datagrams to receive, length of buffers-  -> MessageFlags 'Receive -- ^ Flags-  -> IO (Either Errno CInt)-uninterruptibleReceiveMultipleMessageC !s (MutablePrimArray lens) (MutablePrimArray addrs) (MutableUnliftedArray (MutableUnliftedArray# payloads)) !msgCount !flags =-  c_unsafe_recvmmsg_sockaddr_in s lens addrs payloads msgCount flags >>= errorsFromInt---- | All three buffer arguments need to have the same length (in elements, not bytes).--- This discards the source addresses.-uninterruptibleReceiveMultipleMessageD ::-     Fd -- ^ Socket-  -> MutablePrimArray RealWorld CInt -- ^ Buffer for payload lengths-  -> MutableUnliftedArray RealWorld (MutableByteArray RealWorld) -- ^ Buffers for payloads-  -> CUInt -- ^ Maximum number of datagrams to receive, length of buffers-  -> MessageFlags 'Receive -- ^ Flags-  -> IO (Either Errno CInt)-uninterruptibleReceiveMultipleMessageD !s (MutablePrimArray lens) (MutableUnliftedArray (MutableUnliftedArray# payloads)) !msgCount !flags =-  c_unsafe_recvmmsg_sockaddr_discard s lens payloads msgCount flags >>= errorsFromInt---- This sets up an array of mmsghdr. Each msghdr has msg_iov set to--- be an array of iovec with a single element.-initializeMultipleMessageHeadersWithoutSockAddr ::-     MutableUnliftedArray RealWorld (MutableByteArray RealWorld) -- buffers-  -> Addr -- array of iovec-  -> Addr -- array of message headers-  -> CSize -- message size-  -> CUInt -- message count-  -> IO ()-initializeMultipleMessageHeadersWithoutSockAddr bufs iovecsAddr mmsgHdrsAddr msgSize msgCount =-  let go !ix !iovecAddr !mmsgHdrAddr = if ix < cuintToInt msgCount-        then do-          pokeMultipleMessageHeader mmsgHdrAddr nullAddr 0 iovecAddr 1 nullAddr 0 mempty 0-          initializeIOVector bufs iovecAddr msgSize ix-          go (ix + 1) (plusAddr iovecAddr (cintToInt S.sizeofIOVector)) (plusAddr mmsgHdrAddr (cintToInt LST.sizeofMultipleMessageHeader))-        else pure ()-   in go 0 iovecsAddr mmsgHdrsAddr---- This sets up an array of mmsghdr. Each msghdr has msg_iov set to--- be an array of iovec with a single element. One giant buffer with--- space for all of the @sockaddr@s is used.-initializeMultipleMessageHeadersWithSockAddr ::-     MutableUnliftedArray RealWorld (MutableByteArray RealWorld)-  -> Addr -- array of iovec-  -> Addr -- array of message headers-  -> Addr -- array of sockaddrs-  -> CInt -- expected sockaddr size-  -> CSize -- message size-  -> CUInt -- message count-  -> IO ()-initializeMultipleMessageHeadersWithSockAddr bufs iovecsAddr0 mmsgHdrsAddr0 sockaddrsAddr0 sockaddrSize msgSize msgCount =-  let go !ix !iovecAddr !mmsgHdrAddr !sockaddrAddr = if ix < cuintToInt msgCount-        then do-          pokeMultipleMessageHeader mmsgHdrAddr sockaddrAddr sockaddrSize iovecAddr 1 nullAddr 0 mempty 0-          initializeIOVector bufs iovecAddr msgSize ix-          go (ix + 1)-            (plusAddr iovecAddr (cintToInt S.sizeofIOVector))-            (plusAddr mmsgHdrAddr (cintToInt LST.sizeofMultipleMessageHeader))-            (plusAddr sockaddrAddr (cintToInt sockaddrSize))-        else pure ()-   in go 0 iovecsAddr0 mmsgHdrsAddr0 sockaddrsAddr0--ptrToAddr :: Ptr Word8 -> Addr-ptrToAddr (Ptr x) = Addr x---- Initialize a single iovec. We write the pinned byte array into--- both the iov_base field and into an unlifted array.-initializeIOVector ::-     MutableUnliftedArray RealWorld (MutableByteArray RealWorld)-  -> Addr-  -> CSize-  -> Int-  -> IO ()-initializeIOVector bufs iovecAddr msgSize ix = do-  buf <- PM.newPinnedByteArray (csizeToInt msgSize)-  PM.writeUnliftedArray bufs ix buf-  S.pokeIOVectorBase iovecAddr (ptrToAddr (PM.mutableByteArrayContents buf))-  S.pokeIOVectorLength iovecAddr msgSize---- Freeze a slice of the mutable byte arrays inside the unlifted array,--- shrinking the byte arrays before doing so.-shrinkAndFreezeMessages ::-     CSize -- Full size of each buffer-  -> CInt -- Expected sockaddr size-  -> Int -- Actual number of received messages-  -> MutableUnliftedArray RealWorld (MutableByteArray RealWorld)-  -> Addr -- Array of mmsghdr-  -> IO (CInt,CUInt,UnliftedArray ByteArray)-shrinkAndFreezeMessages !bufSize !expSockAddrSize !n !bufs !mmsghdr0 = do-  r <- PM.unsafeNewUnliftedArray n-  go r 0 0 0 mmsghdr0-  where-  go !r !validation !ix !maxMsgSz !mmsghdr = if ix < n-    then do-      sz <- LST.peekMultipleMessageHeaderLength mmsghdr-      sockaddrSz <- LST.peekMultipleMessageHeaderNameLength mmsghdr-      buf <- PM.readUnliftedArray bufs ix-      when (cuintToInt sz < csizeToInt bufSize) (shrinkMutableByteArray buf (cuintToInt sz))-      PM.writeUnliftedArray r ix =<< PM.unsafeFreezeByteArray buf-      go r (validation .|. (sockaddrSz - expSockAddrSize)) (ix + 1) (max maxMsgSz sz)-        (plusAddr mmsghdr (cintToInt LST.sizeofMultipleMessageHeader))-    else do-      a <- PM.unsafeFreezeUnliftedArray r-      pure (validation,maxMsgSz,a)-#endif--pokeMultipleMessageHeader :: Addr -> Addr -> CInt -> Addr -> CSize -> Addr -> CSize -> MessageFlags 'Receive -> CUInt -> IO ()-pokeMultipleMessageHeader mmsgHdrAddr a b c d e f g len = do-  LST.pokeMultipleMessageHeaderName mmsgHdrAddr a-  LST.pokeMultipleMessageHeaderNameLength mmsgHdrAddr b-  LST.pokeMultipleMessageHeaderIOVector mmsgHdrAddr c-  LST.pokeMultipleMessageHeaderIOVectorLength mmsgHdrAddr d-  LST.pokeMultipleMessageHeaderControl mmsgHdrAddr e-  LST.pokeMultipleMessageHeaderControlLength mmsgHdrAddr f-  LST.pokeMultipleMessageHeaderFlags mmsgHdrAddr g-  LST.pokeMultipleMessageHeaderLength mmsgHdrAddr len- shrinkMutableByteArray :: MutableByteArray RealWorld -> Int -> IO () shrinkMutableByteArray (MutableByteArray arr) (I# sz) =   PM.primitive_ (shrinkMutableByteArray# arr sz) --- | Variant of 'Posix.Socket.uninterruptibleAccept' that allows setting---   flags on the newly-accepted connection.+{- | Variant of 'Posix.Socket.uninterruptibleAccept' that allows setting+  flags on the newly-accepted connection.+-} uninterruptibleAccept4 ::-     Fd -- ^ Listening socket-  -> CInt -- ^ Maximum socket address size-  -> SocketFlags -- ^ Set non-blocking and close-on-exec without extra syscall-  -> IO (Either Errno (CInt,SocketAddress,Fd)) -- ^ Peer information and connected socket-{-# inline uninterruptibleAccept4 #-}+  -- | Listening socket+  Fd ->+  -- | Maximum socket address size+  CInt ->+  -- | Set non-blocking and close-on-exec without extra syscall+  SocketFlags ->+  -- | Peer information and connected socket+  IO (Either Errno (CInt, SocketAddress, Fd))+{-# INLINE uninterruptibleAccept4 #-} uninterruptibleAccept4 !sock !maxSz !flags = do   sockAddrBuf@(MutableByteArray sockAddrBuf#) <- PM.newByteArray (cintToInt maxSz)   lenBuf@(MutableByteArray lenBuf#) <- PM.newByteArray (PM.sizeOf (undefined :: CInt))@@ -390,16 +131,20 @@         then shrinkMutableByteArray sockAddrBuf (cintToInt sz)         else pure ()       sockAddr <- PM.unsafeFreezeByteArray sockAddrBuf-      pure (Right (sz,SocketAddress sockAddr,r))+      pure (Right (sz, SocketAddress sockAddr, r))     else fmap Left getErrno --- | Variant of 'uninterruptibleAccept4' that requests that the kernel not--- include the socket address in its reponse.+{- | Variant of 'uninterruptibleAccept4' that requests that the kernel not+include the socket address in its reponse.+-} uninterruptibleAccept4_ ::-     Fd -- ^ Listening socket-  -> SocketFlags -- ^ Set non-blocking and close-on-exec without extra syscall-  -> IO (Either Errno Fd) -- ^ Connected socket-{-# inline uninterruptibleAccept4_ #-}+  -- | Listening socket+  Fd ->+  -- | Set non-blocking and close-on-exec without extra syscall+  SocketFlags ->+  -- | Connected socket+  IO (Either Errno Fd)+{-# INLINE uninterruptibleAccept4_ #-} uninterruptibleAccept4_ !sock !flags = do   r <- c_unsafe_ptr_accept4 sock nullPtr nullPtr flags   if r > (-1)@@ -408,32 +153,3 @@  cintToInt :: CInt -> Int cintToInt = fromIntegral--cuintToInt :: CUInt -> Int-cuintToInt = fromIntegral--csizeToInt :: CSize -> Int-csizeToInt = fromIntegral--cssizeToInt :: CSsize -> Int-cssizeToInt = fromIntegral--errorsFromInt :: CInt -> IO (Either Errno CInt)-{-# inline errorsFromInt #-}-errorsFromInt r = if r > (-1)-  then pure (Right r)-  else fmap Left getErrno--touchMutableByteArray :: MutableByteArray RealWorld -> IO ()-touchMutableByteArray (MutableByteArray x) = touchMutableByteArray# x--touchMutableByteArray# :: MutableByteArray# RealWorld -> IO ()-touchMutableByteArray# x = IO $ \s -> case touch# x s of s' -> (# s', () #)--#if defined(UNLIFTEDARRAYFUNCTIONS)-touchMutableUnliftedArray :: MutableUnliftedArray RealWorld a -> IO ()-touchMutableUnliftedArray (MutableUnliftedArray x) = touchMutableUnliftedArray# x--touchMutableUnliftedArray# :: MutableUnliftedArray# RealWorld a -> IO ()-touchMutableUnliftedArray# x = IO $ \s -> case touch# x s of s' -> (# s', () #)-#endif
src/Linux/Socket/Types.hsc view
@@ -75,7 +75,7 @@  -- newtype Collection :: Type -> Type where --   Collection :: !(Ptr a) -> Collection a--- +-- -- indexCollection :: Ptr a --   => Collection a -> Int -> IO (Ptr a) -- indexCollection (Collection p) n = advancePtr p n@@ -88,12 +88,12 @@ --   , controlLength :: !CSize --   , flags :: !(MessageFlags Receive) --   }--- +-- -- data IOVector = IOVector --   { base :: !Addr --   , length :: !CSize --   }--- +-- -- data ControlMessageHeader = ControlMessageHeader --   { length :: !CInt --   , level :: !CInt
src/Posix/Directory.hs view
@@ -1,18 +1,15 @@-{-# language BangPatterns #-}-{-# language MagicHash #-}-{-# language LambdaCase #-}-{-# language UnboxedTuples #-}+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE LambdaCase #-}  module Posix.Directory   ( getCurrentWorkingDirectory   ) where  import Data.Primitive (ByteArray)-import GHC.Exts (Ptr(..))+import Foreign.C.Error (Errno, eRANGE, getErrno)+import Foreign.C.Types (CChar, CSize (..)) import Foreign.Ptr (nullPtr)-import Foreign.C.Error (Errno,eRANGE,getErrno)-import Foreign.C.Types (CChar,CSize(..))-import GHC.IO (IO(..))+import GHC.Exts (Ptr (..))  import qualified Data.Primitive as PM import qualified Foreign.Storable as FS@@ -20,11 +17,13 @@ foreign import ccall safe "getcwd"   c_getcwd :: Ptr CChar -> CSize -> IO (Ptr CChar) --- | Get the current working directory without using the system locale---   to convert it to text. This is implemented with a safe FFI call---   since it may block.+{- | Get the current working directory without using the system locale+  to convert it to text. This is implemented with a safe FFI call+  since it may block.+-} getCurrentWorkingDirectory :: IO (Either Errno ByteArray)-getCurrentWorkingDirectory = go (4096 - chunkOverhead) where+getCurrentWorkingDirectory = go (4096 - chunkOverhead)+ where   go !sz = do     -- It may be nice to add a variant of getCurrentWorkingDirectory that     -- allow the user to supply an initial pinned buffer. I'm not sure@@ -59,10 +58,10 @@ -- There must be a null byte present or bad things will happen. -- This will return a nonnegative number. findNullByte :: Ptr CChar -> IO Int-findNullByte = go 0 where+findNullByte = go 0+ where   go :: Int -> Ptr CChar -> IO Int   go !ix !ptr = do     FS.peekElemOff ptr ix >>= \case       0 -> pure ix       _ -> go (ix + 1) ptr-
src/Posix/File.hs view
@@ -1,9 +1,8 @@-{-# language BangPatterns #-}-{-# language BinaryLiterals #-}-{-# language LambdaCase #-}-{-# language MagicHash #-}-{-# language TypeApplications #-}-{-# language UnliftedFFITypes #-}+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE BinaryLiterals #-}+{-# LANGUAGE MagicHash #-}+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE UnliftedFFITypes #-}  module Posix.File   ( -- * Functions@@ -13,6 +12,7 @@   , uninterruptibleWriteBytes   , uninterruptibleWriteBytesCompletely   , uninterruptibleWriteBytesCompletelyErrno+  , uninterruptibleReadMutableByteArray   , writeBytesCompletelyErrno   , uninterruptibleOpen   , uninterruptibleOpenMode@@ -25,49 +25,53 @@   , uninterruptibleErrorlessClose   , uninterruptibleUnlink   , uninterruptibleLink+     -- * Types-  , AccessMode(..)-  , CreationFlags(..)-  , DescriptorFlags(..)-  , StatusFlags(..)+  , AccessMode (..)+  , CreationFlags (..)+  , DescriptorFlags (..)+  , StatusFlags (..)+     -- * File Descriptor Flags   , Types.nonblocking   , Types.append   , isReadOnly   , isWriteOnly   , isReadWrite+     -- * Open Access Mode   , Types.readOnly   , Types.writeOnly   , Types.readWrite+     -- * File Creation Flags   , Types.create   , Types.truncate   , Types.exclusive   ) where -import Assertion (assertByteArrayPinned,assertMutableByteArrayPinned)-import Data.Bits ((.&.),(.|.))-import Data.Primitive (ByteArray(..))-import Foreign.C.Error (Errno(Errno),getErrno,eOK)-import Foreign.C.String.Managed (ManagedCString(..))-import Foreign.C.Types (CInt(..),CSize(..))-import GHC.Exts (ByteArray#,MutableByteArray#,RealWorld)-import Posix.File.Types (CreationFlags(..),AccessMode(..),StatusFlags(..))-import Posix.File.Types (DescriptorFlags(..))-import System.Posix.Types (Fd(..),CSsize(..),CMode(..))-import Data.Bytes.Types (Bytes(Bytes))-import Data.Primitive (MutableByteArray(MutableByteArray))+import Assertion (assertByteArrayPinned, assertMutableByteArrayPinned)+import Data.Bits ((.&.), (.|.))+import Data.Bytes.Types (Bytes (Bytes))+import Data.Primitive (ByteArray (..), MutableByteArray (MutableByteArray))+import Foreign.C.Error (Errno (Errno), eOK, getErrno)+import Foreign.C.String.Managed (ManagedCString (..))+import Foreign.C.Types (CInt (..), CSize (..))+import GHC.Exts (ByteArray#, MutableByteArray#, RealWorld)+import Posix.File.Types (AccessMode (..), CreationFlags (..), DescriptorFlags (..), StatusFlags (..))+import System.Posix.Types (CMode (..), CSsize (..), Fd (..))  import qualified Posix.File.Types as Types --- | Get file descriptor flags. This uses the unsafe FFI to--- perform @fcntl(fd,F_GETFD)@.+{- | Get file descriptor flags. This uses the unsafe FFI to+perform @fcntl(fd,F_GETFD)@.+-} uninterruptibleGetDescriptorFlags :: Fd -> IO (Either Errno DescriptorFlags) uninterruptibleGetDescriptorFlags !fd = c_getFdFlags fd >>= errorsFromDescriptorFlags --- | Get file status flags. This uses the unsafe FFI to--- perform @fcntl(fd,F_GETFL)@.+{- | Get file status flags. This uses the unsafe FFI to+perform @fcntl(fd,F_GETFL)@.+-} uninterruptibleGetStatusFlags :: Fd -> IO (Either Errno StatusFlags) uninterruptibleGetStatusFlags !fd = c_getFlFlags fd >>= errorsFromStatusFlags @@ -111,183 +115,257 @@   c_unsafe_close :: Fd -> IO CInt  uninterruptibleOpen ::-     ManagedCString -- ^ NULL-terminated file name-  -> AccessMode -- ^ Access mode-  -> CreationFlags -- ^ Creation flags-  -> StatusFlags -- ^ Status flags-  -> IO (Either Errno Fd)+  -- | NULL-terminated file name+  ManagedCString ->+  -- | Access mode+  AccessMode ->+  -- | Creation flags+  CreationFlags ->+  -- | Status flags+  StatusFlags ->+  IO (Either Errno Fd) uninterruptibleOpen (ManagedCString (ByteArray name)) (AccessMode x) (CreationFlags y) (StatusFlags z) =   c_unsafe_open name (x .|. y .|. z) >>= errorsFromFd --- | Variant of 'uninterruptibleOpen' that does not help the caller with--- the types of the flags.+{- | Variant of 'uninterruptibleOpen' that does not help the caller with+the types of the flags.+-} uninterruptibleOpenUntypedFlags ::-     ManagedCString -- ^ NULL-terminated file name-  -> CInt -- ^ Flags-  -> IO (Either Errno Fd)+  -- | NULL-terminated file name+  ManagedCString ->+  -- | Flags+  CInt ->+  IO (Either Errno Fd) uninterruptibleOpenUntypedFlags (ManagedCString (ByteArray name)) x =   c_unsafe_open name x >>= errorsFromFd --- | Variant of 'uninterruptibleOpenMode' that does not help the caller with--- the types of the flags.+{- | Variant of 'uninterruptibleOpenMode' that does not help the caller with+the types of the flags.+-} uninterruptibleOpenModeUntypedFlags ::-     ManagedCString -- ^ NULL-terminated file name-  -> CInt -- ^ Flags-  -> CMode -- ^ Mode-  -> IO (Either Errno Fd)+  -- | NULL-terminated file name+  ManagedCString ->+  -- | Flags+  CInt ->+  -- | Mode+  CMode ->+  IO (Either Errno Fd) uninterruptibleOpenModeUntypedFlags (ManagedCString (ByteArray name)) !x !mode =   c_unsafe_open_mode name x mode >>= errorsFromFd  uninterruptibleOpenMode ::-     ManagedCString -- ^ NULL-terminated file name-  -> AccessMode -- ^ Access mode, should include @O_CREAT@-  -> CreationFlags -- ^ Creation flags-  -> StatusFlags -- ^ Status flags-  -> CMode -- ^ Permissions assigned to newly created file-  -> IO (Either Errno Fd)+  -- | NULL-terminated file name+  ManagedCString ->+  -- | Access mode, should include @O_CREAT@+  AccessMode ->+  -- | Creation flags+  CreationFlags ->+  -- | Status flags+  StatusFlags ->+  -- | Permissions assigned to newly created file+  CMode ->+  IO (Either Errno Fd) uninterruptibleOpenMode (ManagedCString (ByteArray name)) (AccessMode x) (CreationFlags y) (StatusFlags z) !mode =   c_unsafe_open_mode name (x .|. y .|. z) mode >>= errorsFromFd  errorsFromDescriptorFlags :: DescriptorFlags -> IO (Either Errno DescriptorFlags)-errorsFromDescriptorFlags r@(DescriptorFlags x) = if x > (-1)-  then pure (Right r)-  else fmap Left getErrno+errorsFromDescriptorFlags r@(DescriptorFlags x) =+  if x > (-1)+    then pure (Right r)+    else fmap Left getErrno  errorsFromStatusFlags :: StatusFlags -> IO (Either Errno StatusFlags)-errorsFromStatusFlags r@(StatusFlags x) = if x > (-1)-  then pure (Right r)-  else fmap Left getErrno+errorsFromStatusFlags r@(StatusFlags x) =+  if x > (-1)+    then pure (Right r)+    else fmap Left getErrno --- | Wrapper for @write(2)@ that takes a slice of bytes and an offset.--- The byte array backing the slice does not need to be pinned.+{- | Wrapper for @write(2)@ that takes a slice of bytes and an offset.+The byte array backing the slice does not need to be pinned.+-} uninterruptibleWriteBytesCompletely ::-     Fd -- ^ File descriptor-  -> Bytes -- ^ Source bytes-  -> IO (Either Errno ())+  -- | File descriptor+  Fd ->+  -- | Source bytes+  Bytes ->+  IO (Either Errno ()) uninterruptibleWriteBytesCompletely !fd !b = do   e <- uninterruptibleWriteBytesCompletelyErrno fd b   if e == eOK     then pure (Right ())     else pure (Left e) --- | Variant of 'uninterruptibleWriteBytesCompletely' that uses errno 0--- to communicate success.+{- | Variant of 'uninterruptibleWriteBytesCompletely' that uses errno 0+to communicate success.+-} uninterruptibleWriteBytesCompletelyErrno ::-     Fd -- ^ File descriptor-  -> Bytes -- ^ Source bytes-  -> IO Errno+  -- | File descriptor+  Fd ->+  -- | Source bytes+  Bytes ->+  IO Errno uninterruptibleWriteBytesCompletelyErrno !fd (Bytes (ByteArray buf) off len) =   c_unsafe_bytearray_write_loop fd buf off (fromIntegral @Int @CSize len) --- | Wrapper for @write(2)@ that takes a slice of bytes and an offset.--- The byte array backing the slice must be pinned.+{- | Wrapper for @write(2)@ that takes a slice of bytes and an offset.+The byte array backing the slice must be pinned.+-} writeBytesCompletelyErrno ::-     Fd -- ^ File descriptor-  -> Bytes -- ^ Source bytes-  -> IO Errno+  -- | File descriptor+  Fd ->+  -- | Source bytes+  Bytes ->+  IO Errno writeBytesCompletelyErrno !fd (Bytes buf0 off len) =   let !(ByteArray buf1) = assertByteArrayPinned buf0    in c_safe_bytearray_write_loop fd buf1 off (fromIntegral @Int @CSize len) --- | Wrapper for @write(2)@ that takes a slice of bytes and an offset.--- The byte array backing the slice does not need to be pinned.+{- | Wrapper for @write(2)@ that takes a slice of bytes and an offset.+The byte array backing the slice does not need to be pinned.+-} uninterruptibleWriteBytes ::-     Fd -- ^ File descriptor-  -> Bytes -- ^ Source bytes-  -> IO (Either Errno CSize) -- ^ Number of bytes written+  -- | File descriptor+  Fd ->+  -- | Source bytes+  Bytes ->+  -- | Number of bytes written+  IO (Either Errno CSize) uninterruptibleWriteBytes !fd (Bytes (ByteArray buf) off len) =   c_unsafe_bytearray_write fd buf off (fromIntegral @Int @CSize len)     >>= errorsFromSize --- | Wrapper for @write(2)@ that takes a byte array and an offset.--- The byte array does not need to be pinned.+{- | Wrapper for @write(2)@ that takes a byte array and an offset.+The byte array does not need to be pinned.+-} uninterruptibleWriteByteArray ::-     Fd -- ^ Socket-  -> ByteArray -- ^ Source byte array-  -> Int -- ^ Offset into source array-  -> CSize -- ^ Length in bytes-  -> IO (Either Errno CSize) -- ^ Number of bytes pushed to send buffer+  -- | Socket+  Fd ->+  -- | Source byte array+  ByteArray ->+  -- | Offset into source array+  Int ->+  -- | Length in bytes+  CSize ->+  -- | Number of bytes pushed to send buffer+  IO (Either Errno CSize) uninterruptibleWriteByteArray !fd (ByteArray buf) !off !len =   c_unsafe_bytearray_write fd buf off len >>= errorsFromSize --- | Wrapper for @write(2)@ that takes a byte array and an offset.--- Uses @safe@ FFI. The byte array must be pinned.+{- | Wrapper for @write(2)@ that takes a byte array and an offset.+Uses @safe@ FFI. The byte array must be pinned.+-} writeByteArray ::-     Fd -- ^ File descriptor-  -> ByteArray -- ^ Source byte array-  -> Int -- ^ Offset into source array-  -> CSize -- ^ Length in bytes-  -> IO (Either Errno CSize) -- ^ Number of bytes pushed to send buffer+  -- | File descriptor+  Fd ->+  -- | Source byte array+  ByteArray ->+  -- | Offset into source array+  Int ->+  -- | Length in bytes+  CSize ->+  -- | Number of bytes pushed to send buffer+  IO (Either Errno CSize) writeByteArray !fd !buf0 !off !len =   let !(ByteArray buf1) = assertByteArrayPinned buf0    in c_safe_bytearray_write fd buf1 off len >>= errorsFromSize  -- writeByteArrayCompletely :: --- | Variant of 'writeByteArray' that operates on mutable byte array.--- Uses @safe@ FFI. The byte array must be pinned.+{- | Variant of 'writeByteArray' that operates on mutable byte array.+Uses @safe@ FFI. The byte array must be pinned.+-} writeMutableByteArray ::-     Fd -- ^ File descriptor-  -> MutableByteArray RealWorld -- ^ Source byte array-  -> Int -- ^ Offset into source array-  -> CSize -- ^ Length in bytes-  -> IO (Either Errno CSize) -- ^ Number of bytes pushed to send buffer+  -- | File descriptor+  Fd ->+  -- | Source byte array+  MutableByteArray RealWorld ->+  -- | Offset into source array+  Int ->+  -- | Length in bytes+  CSize ->+  -- | Number of bytes pushed to send buffer+  IO (Either Errno CSize) writeMutableByteArray !fd !buf0 !off !len =   let !(MutableByteArray buf1) = assertMutableByteArrayPinned buf0    in c_safe_mutablebytearray_write fd buf1 off len >>= errorsFromSize +uninterruptibleReadMutableByteArray ::+  -- | File descriptor+  Fd ->+  -- | Destination+  MutableByteArray RealWorld ->+  -- | Destination offset+  Int ->+  -- | Length in bytes+  CSize ->+  -- | Number of bytes received+  IO (Either Errno CSize)+uninterruptibleReadMutableByteArray !fd !(MutableByteArray !b) !doff !dlen = do+  c_unsafe_mutable_byte_array_read fd b doff dlen >>= errorsFromSize+ errorsFromSize :: CSsize -> IO (Either Errno CSize)-errorsFromSize r = if r > (-1)-  then pure (Right (cssizeToCSize r))-  else fmap Left getErrno+errorsFromSize r =+  if r > (-1)+    then pure (Right (cssizeToCSize r))+    else fmap Left getErrno  errorsFromFd :: Fd -> IO (Either Errno Fd)-errorsFromFd r = if r > (-1)-  then pure (Right r)-  else fmap Left getErrno+errorsFromFd r =+  if r > (-1)+    then pure (Right r)+    else fmap Left getErrno  uninterruptibleLink ::-     ManagedCString -- ^ Path to existing file-  -> ManagedCString -- ^ Path to new file-  -> IO (Either Errno ())+  -- | Path to existing file+  ManagedCString ->+  -- | Path to new file+  ManagedCString ->+  IO (Either Errno ()) uninterruptibleLink (ManagedCString (ByteArray x)) (ManagedCString (ByteArray y)) =   c_unsafe_link x y >>= errorsFromInt_  uninterruptibleUnlink ::-     ManagedCString -- ^ File name-  -> IO (Either Errno ())+  -- | File name+  ManagedCString ->+  IO (Either Errno ()) uninterruptibleUnlink (ManagedCString (ByteArray x)) =   c_unsafe_unlink x >>= errorsFromInt_ --- | Close a file descriptor.---   The <http://pubs.opengroup.org/onlinepubs/009696899/functions/close.html POSIX specification>---   includes more details. This uses the safe FFI.+{- | Close a file descriptor.+  The <http://pubs.opengroup.org/onlinepubs/009696899/functions/close.html POSIX specification>+  includes more details. This uses the safe FFI.+-} close ::-     Fd -- ^ Socket-  -> IO (Either Errno ())+  -- | Socket+  Fd ->+  IO (Either Errno ()) close fd = c_safe_close fd >>= errorsFromInt_ --- | Close a file descriptor. This uses the unsafe FFI. According to the---   <http://pubs.opengroup.org/onlinepubs/009696899/functions/close.html POSIX specification>,---   "If @fildes@ refers to a socket, @close()@ shall cause the socket to---   be destroyed. If the socket is in connection-mode, and the @SO_LINGER@---   option is set for the socket with non-zero linger time, and the socket---   has untransmitted data, then @close()@ shall block for up to the current---   linger interval until all data is transmitted."+{- | Close a file descriptor. This uses the unsafe FFI. According to the+  <http://pubs.opengroup.org/onlinepubs/009696899/functions/close.html POSIX specification>,+  "If @fildes@ refers to a socket, @close()@ shall cause the socket to+  be destroyed. If the socket is in connection-mode, and the @SO_LINGER@+  option is set for the socket with non-zero linger time, and the socket+  has untransmitted data, then @close()@ shall block for up to the current+  linger interval until all data is transmitted."+-} uninterruptibleClose ::-     Fd -- ^ Socket-  -> IO (Either Errno ())+  -- | Socket+  Fd ->+  IO (Either Errno ()) uninterruptibleClose fd = c_unsafe_close fd >>= errorsFromInt_ --- | Close a file descriptor with the unsafe FFI. Do not check for errors.---   It is only appropriate to use this when a file descriptor is being---   closed to handle an exceptional case. Since the user will want to---   propogate the original exception, the exception provided by---   'uninterruptibleClose' would just be discarded. This function allows us---   to potentially avoid an additional FFI call to 'getErrno'.+{- | Close a file descriptor with the unsafe FFI. Do not check for errors.+  It is only appropriate to use this when a file descriptor is being+  closed to handle an exceptional case. Since the user will want to+  propogate the original exception, the exception provided by+  'uninterruptibleClose' would just be discarded. This function allows us+  to potentially avoid an additional FFI call to 'getErrno'.+-} uninterruptibleErrorlessClose ::-     Fd -- ^ Socket-  -> IO ()+  -- | Socket+  Fd ->+  IO () uninterruptibleErrorlessClose fd = do   _ <- c_unsafe_close fd   pure ()@@ -309,7 +387,10 @@ -- success and negative one to indicate failure without including -- additional information in the value. errorsFromInt_ :: CInt -> IO (Either Errno ())-errorsFromInt_ r = if r == 0-  then pure (Right ())-  else fmap Left getErrno+errorsFromInt_ r =+  if r == 0+    then pure (Right ())+    else fmap Left getErrno +foreign import ccall unsafe "HaskellPosix.h read_offset"+  c_unsafe_mutable_byte_array_read :: Fd -> MutableByteArray# RealWorld -> Int -> CSize -> IO CSsize
src/Posix/MessageQueue.hs view
@@ -1,65 +1,82 @@-{-# language BangPatterns #-}-{-# language MagicHash #-}-{-# language UnboxedTuples #-}-{-# language UnliftedFFITypes #-}+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE MagicHash #-}+{-# LANGUAGE UnliftedFFITypes #-}+ module Posix.MessageQueue   ( open   , uninterruptibleReceiveByteArray   , uninterruptibleSendBytes+     -- * Types-  , AccessMode(..)-  , CreationFlags(..)-  , StatusFlags(..)+  , AccessMode (..)+  , CreationFlags (..)+  , StatusFlags (..)+     -- * Open Access Mode   , F.readOnly   , F.writeOnly   , F.readWrite+     -- * Open Flags   , F.nonblocking   ) where +import qualified Control.Monad.Primitive as PM import Data.Bits ((.|.))-import GHC.Exts (RealWorld,ByteArray#,MutableByteArray#,Addr#)-import GHC.Exts (Int(I#))-import System.Posix.Types (Fd(..),CSsize(..))-import Foreign.C.Types (CInt(..),CSize(..),CUInt(..))-import Foreign.C.Error (Errno,getErrno)+import Data.Bytes.Types (Bytes (Bytes))+import Data.Primitive (ByteArray (..), MutableByteArray (..))+import qualified Data.Primitive as PM+import Foreign.C.Error (Errno, getErrno) import Foreign.C.String (CString)-import Data.Primitive (MutableByteArray(..),ByteArray(..))-import Data.Bytes.Types (Bytes(Bytes))-import Posix.File.Types (CreationFlags(..),AccessMode(..),StatusFlags(..))+import Foreign.C.Types (CInt (..), CSize (..), CUInt (..))+import GHC.Exts (Addr#, ByteArray#, Int (I#), MutableByteArray#, RealWorld) import qualified GHC.Exts as Exts-import qualified Data.Primitive as PM-import qualified Control.Monad.Primitive as PM+import Posix.File.Types (AccessMode (..), CreationFlags (..), StatusFlags (..)) import qualified Posix.File.Types as F+import System.Posix.Types (CSsize (..), Fd (..))  foreign import ccall unsafe "mqueue.h mq_receive"-  c_unsafe_mq_receive :: Fd -> MutableByteArray# RealWorld-                      -> CSize -> Addr# -> IO CSsize+  c_unsafe_mq_receive ::+    Fd ->+    MutableByteArray# RealWorld ->+    CSize ->+    Addr# ->+    IO CSsize  foreign import ccall unsafe "mqueue.h mq_send_offset"-  c_unsafe_mq_send_offset :: Fd-    -> ByteArray# -> Int -> CSize -> CUInt -> IO CInt+  c_unsafe_mq_send_offset ::+    Fd ->+    ByteArray# ->+    Int ->+    CSize ->+    CUInt ->+    IO CInt  foreign import ccall safe "mqueue.h mq_open"   c_safe_mq_open :: CString -> CInt -> IO Fd  open ::-     CString -- ^ NULL-terminated name of queue, must start with slash-  -> AccessMode -- ^ Access mode-  -> CreationFlags -- ^ Creation flags-  -> StatusFlags -- ^ Status flags-  -> IO (Either Errno Fd)+  -- | NULL-terminated name of queue, must start with slash+  CString ->+  -- | Access mode+  AccessMode ->+  -- | Creation flags+  CreationFlags ->+  -- | Status flags+  StatusFlags ->+  IO (Either Errno Fd) open !name (AccessMode x) (CreationFlags y) (StatusFlags z) =   c_safe_mq_open name (x .|. y .|. z) >>= errorsFromFd  uninterruptibleReceiveByteArray ::-     Fd -- ^ Message queue-  -> CSize -- ^ Maximum length of message-  -> IO (Either Errno ByteArray)+  -- | Message queue+  Fd ->+  -- | Maximum length of message+  CSize ->+  IO (Either Errno ByteArray) uninterruptibleReceiveByteArray !fd !len = do-  m@(MutableByteArray m# ) <- PM.newByteArray (csizeToInt len)-  r <- c_unsafe_mq_receive fd m# len Exts.nullAddr# +  m@(MutableByteArray m#) <- PM.newByteArray (csizeToInt len)+  r <- c_unsafe_mq_receive fd m# len Exts.nullAddr#   case r of     (-1) -> fmap Left getErrno     _ -> do@@ -69,14 +86,17 @@       pure (Right a)  uninterruptibleSendBytes ::-     Fd -- ^ Message queue-  -> Bytes -- ^ Message-  -> CUInt -- ^ Priority-  -> IO (Either Errno ())+  -- | Message queue+  Fd ->+  -- | Message+  Bytes ->+  -- | Priority+  CUInt ->+  IO (Either Errno ()) uninterruptibleSendBytes !fd (Bytes (ByteArray arr) off len) pri =   c_unsafe_mq_send_offset fd arr off (intToCSize len) pri     >>= errorsFromInt_-  + shrinkMutableByteArray :: MutableByteArray RealWorld -> Int -> IO () shrinkMutableByteArray (MutableByteArray arr) (I# sz) =   PM.primitive_ (Exts.shrinkMutableByteArray# arr sz)@@ -94,12 +114,13 @@ -- success and negative one to indicate failure without including -- additional information in the value. errorsFromInt_ :: CInt -> IO (Either Errno ())-errorsFromInt_ r = if r == 0-  then pure (Right ())-  else fmap Left getErrno+errorsFromInt_ r =+  if r == 0+    then pure (Right ())+    else fmap Left getErrno  errorsFromFd :: Fd -> IO (Either Errno Fd)-errorsFromFd r = if r > (-1)-  then pure (Right r)-  else fmap Left getErrno-+errorsFromFd r =+  if r > (-1)+    then pure (Right r)+    else fmap Left getErrno
src/Posix/Poll.hs view
@@ -1,13 +1,12 @@-{-# language BangPatterns #-}-{-# language MagicHash #-}-{-# language UnliftedFFITypes #-}-{-# language ScopedTypeVariables #-}+{-# LANGUAGE MagicHash #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE UnliftedFFITypes #-}  module Posix.Poll   ( uninterruptiblePoll   , uninterruptiblePollMutablePrimArray-  , PollFd(..)-  , Exchange(..)+  , PollFd (..)+  , Exchange (..)   , PT.input   , PT.output   , PT.error@@ -16,13 +15,13 @@   , PT.isSubeventOf   ) where -import Posix.Types (CNfds(..))-import Foreign.C.Error (Errno,getErrno)-import Foreign.C.Types (CInt(..))+import Data.Primitive (MutablePrimArray (..))+import Foreign.C.Error (Errno, getErrno)+import Foreign.C.Types (CInt (..))+import GHC.Exts (MutableByteArray#, RealWorld) import GHC.Ptr (Ptr)-import GHC.Exts (RealWorld,MutableByteArray#)-import Posix.Poll.Types (PollFd(..),Exchange(..))-import Data.Primitive (MutablePrimArray(..))+import Posix.Poll.Types (Exchange (..), PollFd (..))+import Posix.Types (CNfds (..))  import qualified Posix.Poll.Types as PT @@ -32,23 +31,25 @@ foreign import ccall unsafe "poll.h poll"   c_poll_prim_array :: MutableByteArray# RealWorld -> CNfds -> CInt -> IO CInt --- | The @timeout@ argument is omitted since it is nonsense to choose---   anything other than 0 when using the unsafe FFI.+{- | The @timeout@ argument is omitted since it is nonsense to choose+  anything other than 0 when using the unsafe FFI.+-} uninterruptiblePoll ::-     Ptr PollFd-  -> CNfds-  -> IO (Either Errno CInt)+  Ptr PollFd ->+  CNfds ->+  IO (Either Errno CInt) uninterruptiblePoll pfds n =   c_poll_ptr pfds n 0 >>= errorsFromInt  uninterruptiblePollMutablePrimArray ::-     MutablePrimArray RealWorld PollFd-  -> CNfds-  -> IO (Either Errno CInt)+  MutablePrimArray RealWorld PollFd ->+  CNfds ->+  IO (Either Errno CInt) uninterruptiblePollMutablePrimArray (MutablePrimArray pfds) n =   c_poll_prim_array pfds n 0 >>= errorsFromInt  errorsFromInt :: CInt -> IO (Either Errno CInt)-errorsFromInt r = if r >= 0-  then pure (Right r)-  else fmap Left getErrno+errorsFromInt r =+  if r >= 0+    then pure (Right r)+    else fmap Left getErrno
src/Posix/Poll/Types.hsc view
@@ -11,7 +11,7 @@ {-# language MagicHash #-} {-# language UnboxedTuples #-} {-# language PolyKinds #-}-{-# language TypeInType #-}+{-# language DataKinds #-}  -- This is needed because hsc2hs does not currently handle ticked -- promoted data constructors correctly.@@ -37,12 +37,10 @@ import Prelude hiding (truncate,error)  import Data.Bits ((.|.),(.&.))-import Data.Word (Word8,Word16,Word32,Word64) import Data.Primitive (Prim(..)) import Foreign.C.Types (CInt(..),CShort) import Foreign.Storable (Storable(..))-import GHC.Ptr (Ptr(..))-import GHC.Exts (RealWorld,Int(I##),Int##,(+##),(*##))+import GHC.Exts (Int(I##),Int##,(+##),(*##)) import System.Posix.Types (Fd(..))  import qualified Data.Kind
src/Posix/Select.hs view
@@ -1,5 +1,3 @@ module Posix.Select   (   ) where--
src/Posix/Socket.hs view
@@ -1,1496 +1,1522 @@-{-# language BangPatterns #-}-{-# language CPP #-}-{-# language DataKinds #-}-{-# language DuplicateRecordFields #-}-{-# language GADTSyntax #-}-{-# language KindSignatures #-}-{-# language LambdaCase #-}-{-# language MagicHash #-}-{-# language NamedFieldPuns #-}-{-# language PatternSynonyms #-}-{-# language ScopedTypeVariables #-}-{-# language UnboxedTuples #-}-{-# language UnliftedFFITypes #-}---- | Types and functions related to the POSIX sockets API.---   Unusual characteristics:------   * Any time the standard calls for @socklen_t@, we use---     @CInt@ instead. Linus Torvalds <https://yarchive.net/comp/linux/socklen_t.html writes>---     that \"Any sane library must have @socklen_t@ be the same size as @int@.---     Anything else breaks any BSD socket layer stuff.\"---   * Send and receive each have several variants. They are distinguished by---     the safe\/unsafe FFI use and by the @Addr@\/@ByteArray@/@MutableByteArray@---     buffer type. They all call @send@ or @recv@ exactly once. They do not---     repeatedly make syscalls like some of the functions in @network@.---     Users who want that behavior need to build on top of this package.---   * There are no requirements on the pinnedness of @ByteArray@ arguments---     passed to any of these functions. If wrappers of the safe FFI are---     passed unpinned @ByteArray@ arguments, they will copy the contents---     into pinned memory before invoking the foreign function.-module Posix.Socket-  ( -- * Functions-    -- ** Socket-    uninterruptibleSocket-    -- ** Socket Pair-  , uninterruptibleSocketPair-    -- ** Address Resolution-  , getAddressInfo-  , uninterruptibleFreeAddressInfo-    -- ** Bind-  , uninterruptibleBind-    -- ** Connect-  , connect-  , uninterruptibleConnect-  , uninterruptibleConnectPtr-    -- ** Listen-  , uninterruptibleListen-    -- ** Accept-  , accept-  , uninterruptibleAccept-  , accept_-    -- ** Get Socket Name-  , uninterruptibleGetSocketName-    -- ** Get Socket Option-  , uninterruptibleGetSocketOption-    -- ** Set Socket Option-  , uninterruptibleSetSocketOption-  , uninterruptibleSetSocketOptionByteArray-  , uninterruptibleSetSocketOptionInt-    -- ** Close-  , F.close-  , F.uninterruptibleClose-  , F.uninterruptibleErrorlessClose-    -- ** Shutdown-  , uninterruptibleShutdown-    -- ** Send-  , send-  , sendByteArray-  , sendMutableByteArray-  , uninterruptibleSend-  , uninterruptibleSendByteArray-  , uninterruptibleSendMutableByteArray-    -- ** Send To-  , uninterruptibleSendToByteArray-  , uninterruptibleSendToMutableByteArray-  , uninterruptibleSendToInternet-  , uninterruptibleSendToInternetByteArray-  , uninterruptibleSendToInternetMutableByteArray-    -- ** Write Vector-#if defined(UNLIFTEDARRAYFUNCTIONS)-  , writeVector-#endif-    -- ** Receive-  , receive-  , receiveByteArray-  , uninterruptibleReceive-  , uninterruptibleReceiveMutableByteArray-    -- ** Receive From-  , uninterruptibleReceiveFromMutableByteArray-  , uninterruptibleReceiveFromMutableByteArray_-  , uninterruptibleReceiveFrom_-  , uninterruptibleReceiveFromInternet-  , uninterruptibleReceiveFromInternetMutableByteArray-    -- ** Receive Message-    -- $receiveMessage-#if defined(UNLIFTEDARRAYFUNCTIONS)-  , uninterruptibleReceiveMessageA-  , uninterruptibleReceiveMessageB-#endif-    -- ** Send Message-  , uninterruptibleSendMessageA-  , uninterruptibleSendMessageB-#if defined(UNLIFTEDARRAYFUNCTIONS)-  , uninterruptibleSendByteArrays-#endif-    -- ** Byte-Order Conversion-    -- $conversion-  , hostToNetworkLong-  , hostToNetworkShort-  , networkToHostLong-  , networkToHostShort-    -- * Types-  , Family(..)-  , Type(..)-  , Protocol(..)-  , OptionName(..)-  , OptionValue(..)-  , Level(..)-  , Message(..)-  , MessageFlags(..)-  , ShutdownType(..)-  , AddressInfo-    -- * Socket Address-    -- ** Types-  , SocketAddress(..)-  , PST.SocketAddressInternet(..)-  , PST.SocketAddressUnix(..)-    -- ** Encoding-  , PSP.encodeSocketAddressInternet-  , PSP.encodeSocketAddressUnix-    -- ** Decoding-  , PSP.decodeSocketAddressInternet-  , PSP.indexSocketAddressInternet-    -- ** Sizes-  , PSP.sizeofSocketAddressInternet-    -- * Data Construction-    -- ** Socket Domains-  , pattern PST.Unix-  , pattern PST.Unspecified-  , pattern PST.Internet-  , pattern PST.Internet6-    -- ** Socket Types-  , PST.stream-  , PST.datagram-  , PST.raw-  , PST.sequencedPacket-    -- ** Protocols-  , PST.defaultProtocol-  , PST.rawProtocol-  , PST.icmp-  , PST.tcp-  , PST.udp-  , PST.ip-  , PST.ipv6-    -- ** Receive Flags-  , PST.peek-  , PST.outOfBand-  , PST.waitAll-    -- ** Send Flags-  , PST.noSignal-    -- ** Shutdown Types-  , PST.read-  , PST.write-  , PST.readWrite-    -- ** Socket Levels-  , PST.levelSocket-    -- ** Option Names-  , PST.optionError-  , PST.bindToDevice-  , PST.broadcast-  , PST.reuseAddress-    -- ** Address Info-    -- *** Peek-  , PST.peekAddressInfoFlags-    -- *** Poke-  , PST.pokeAddressInfoFlags-    -- *** Metadata-  , PST.sizeofAddressInfo-    -- ** Message Header-    -- *** Peek-  , PST.peekMessageHeaderName-  , PST.peekMessageHeaderNameLength-  , PST.peekMessageHeaderIOVector-  , PST.peekMessageHeaderIOVectorLength-  , PST.peekMessageHeaderControl-  , PST.peekMessageHeaderControlLength-  , PST.peekMessageHeaderFlags-  , PST.peekControlMessageHeaderLevel-  , PST.peekControlMessageHeaderLength-  , PST.peekControlMessageHeaderType-    -- *** Poke-  , PST.pokeMessageHeaderName-  , PST.pokeMessageHeaderNameLength-  , PST.pokeMessageHeaderIOVector-  , PST.pokeMessageHeaderIOVectorLength-  , PST.pokeMessageHeaderControl-  , PST.pokeMessageHeaderControlLength-  , PST.pokeMessageHeaderFlags-    -- *** Metadata-  , PST.sizeofMessageHeader-    -- ** IO Vector-    -- *** Peek-  , PST.peekIOVectorBase-  , PST.peekIOVectorLength-    -- *** Poke-  , PST.pokeIOVectorBase-  , PST.pokeIOVectorLength-    -- *** Metadata-  , PST.sizeofIOVector-  ) where--import GHC.ByteOrder (ByteOrder(BigEndian,LittleEndian),targetByteOrder)-import GHC.IO (IO(..))-import Data.Primitive.Addr (Addr(..),plusAddr,nullAddr)-import Data.Primitive (MutablePrimArray(..),MutableByteArray(..),ByteArray(..))--#if defined(UNLIFTEDARRAYFUNCTIONS)-import Data.Primitive.Unlifted.Array (MutableUnliftedArray,UnliftedArray,UnliftedArray_(UnliftedArray))-import Data.Primitive.Unlifted.Array (MutableUnliftedArray_(MutableUnliftedArray))-import Data.Primitive.Unlifted.Array.Primops (UnliftedArray#(UnliftedArray#),MutableUnliftedArray#)-#endif--import Data.Primitive.ByteArray.Offset (MutableByteArrayOffset(..))-import Data.Primitive.PrimArray.Offset (MutablePrimArrayOffset(..))-import Data.Word (Word8,Word16,Word32,byteSwap16,byteSwap32)-import Data.Void (Void)-import Foreign.C.Error (Errno(Errno),getErrno)-import Foreign.C.String (CString)-import Foreign.C.Types (CInt(..),CSize(..))-import Foreign.Ptr (nullPtr)-import GHC.Exts (Ptr(Ptr),RealWorld,ByteArray#,MutableByteArray#)-import GHC.Exts (Addr#,TYPE)-import GHC.Exts (Int(I#))-import GHC.Exts (shrinkMutableByteArray#,touch#)-import Posix.Socket.Types (Family(..),Protocol(..),Type(..),SocketAddress(..))-import Posix.Socket.Types (SocketAddressInternet(..))-import Posix.Socket.Types (MessageFlags(..),Message(..),ShutdownType(..))-import Posix.Socket.Types (Level(..),OptionName(..),OptionValue(..))-import Posix.Socket.Types (AddressInfo)-import System.Posix.Types (Fd(..),CSsize(..))--#if MIN_VERSION_base(4,16,0)-import GHC.Exts (RuntimeRep(BoxedRep),Levity(Unlifted))-#else-import GHC.Exts (RuntimeRep(UnliftedRep))-#endif--import qualified Posix.File as F-import qualified Posix.Socket.Types as PST-import qualified Data.Primitive as PM-#if defined(UNLIFTEDARRAYFUNCTIONS)-import qualified Data.Primitive.Unlifted.Array as PM-#endif-import qualified Control.Monad.Primitive as PM-import qualified GHC.Exts as Exts---- This module include operating-system specific code used--- to serialize some of various kind of socket address types.-import qualified Posix.Socket.Platform as PSP---- getaddrinfo cannot use the unsafe ffi-foreign import ccall safe "sys/socket.h getaddrinfo"-  c_safe_getaddrinfo ::-       CString-    -> CString-    -> Ptr AddressInfo-    -> MutableByteArray# RealWorld -- actually a `Ptr (Ptr AddressInfo))`.-    -> IO Errno---- | Free the @addrinfo@ at the pointer.-foreign import ccall safe "sys/socket.h freeaddrinfo"-  uninterruptibleFreeAddressInfo :: Ptr AddressInfo -> IO ()--foreign import ccall unsafe "sys/socket.h socket"-  c_socket :: Family -> Type -> Protocol -> IO Fd--foreign import ccall unsafe "sys/socket.h socketpair"-  c_socketpair :: Family -> Type -> Protocol -> MutableByteArray# RealWorld -> IO CInt--foreign import ccall unsafe "sys/socket.h listen"-  c_listen :: Fd -> CInt -> IO CInt--foreign import ccall unsafe "unistd.h shutdown"-  c_unsafe_shutdown :: Fd -> ShutdownType -> IO CInt---- Per the spec, the type signature of bind is:---   int bind(int socket, const struct sockaddr *address, socklen_t address_len);--- However, here we choose to represent the third argument as--- CInt rather than introducing a type corresponding to socklen_t.--- According to Linus Torvalds, "Any sane library must have socklen_t--- be the same size as int. Anything else breaks any BSD socket layer stuff."--- (https://yarchive.net/comp/linux/socklen_t.html). If a platform--- violates this assumption, this wrapper will be broken on that platform.-foreign import ccall unsafe "sys/socket.h bind"-  c_bind :: Fd -> ByteArray# -> CInt -> IO CInt---- Per the spec, the type signature of accept is:---   int accept(int socket, struct sockaddr *restrict address, socklen_t *restrict address_len);--- The restrict keyword does not matter much for our purposes. See the--- note on c_bind for why we use CInt for socklen_t. Remember that the--- first bytearray argument is actually SocketAddress in the function that--- wraps this one. The second bytearray argument is a pointer to the size.-foreign import ccall safe "sys/socket.h accept"-  c_safe_accept :: Fd-                -> MutableByteArray# RealWorld -- SocketAddress-                -> MutableByteArray# RealWorld -- Ptr CInt-                -> IO Fd-foreign import ccall unsafe "sys/socket.h accept"-  c_unsafe_accept :: Fd-                  -> MutableByteArray# RealWorld -- SocketAddress-                  -> MutableByteArray# RealWorld -- Ptr CInt-                  -> IO Fd--- This variant of accept is used when we do not care about the--- remote sockaddr. We pass null.-foreign import ccall safe "sys/socket.h accept"-  c_safe_ptr_accept :: Fd -> Ptr Void -> Ptr CInt -> IO Fd--foreign import ccall unsafe "sys/socket.h getsockname"-  c_unsafe_getsockname :: Fd-                       -> MutableByteArray# RealWorld -- SocketAddress-                       -> MutableByteArray# RealWorld -- Addr length (Ptr CInt)-                       -> IO CInt--foreign import ccall unsafe "sys/socket.h getsockopt"-  c_unsafe_getsockopt :: Fd-                      -> Level-                      -> OptionName-                      -> MutableByteArray# RealWorld -- Option value-                      -> MutableByteArray# RealWorld -- Option len (Ptr CInt)-                      -> IO CInt--foreign import ccall unsafe "sys/socket.h setsockopt_int"-  c_unsafe_setsockopt_int :: Fd-                          -> Level-                          -> OptionName-                          -> CInt -- option_value-                          -> IO CInt--foreign import ccall unsafe "sys/socket.h setsockopt"-  c_unsafe_setsockopt :: Fd-                      -> Level-                      -> OptionName-                      -> Ptr Void -- option_val-                      -> CInt -- option_len-                      -> IO CInt--foreign import ccall unsafe "sys/socket.h setsockopt"-  c_unsafe_setsockopt_ba :: Fd-                         -> Level-                         -> OptionName-                         -> ByteArray# -- option_val-                         -> CInt -- option_len-                         -> IO CInt---- Per the spec the type signature of connect is:---   int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);--- The bytearray argument is actually SocketAddress.-foreign import ccall safe "sys/socket.h connect"-  c_safe_connect :: Fd -> ByteArray# -> CInt -> IO CInt-foreign import ccall safe "sys/socket.h connect"-  c_safe_mutablebytearray_connect :: Fd -> MutableByteArray# RealWorld -> CInt -> IO CInt-foreign import ccall unsafe "sys/socket.h connect"-  c_unsafe_connect :: Fd -> ByteArray# -> CInt -> IO CInt-foreign import ccall unsafe "sys/socket.h connect"-  c_unsafe_connect_addr :: Fd -> Addr# -> CInt -> IO CInt---- There are several options for wrapping send. Both safe and unsafe--- are useful. Additionally, in the unsafe category, we also--- have the option of writing to either an address or a byte array.--- Unsafe FFI calls guarantee that byte arrays will not be relocated--- while the FFI call is taking place. Safe FFI calls do not have--- this guarantee, so internally we must be careful when using these to only--- provide pinned byte arrays as arguments.-foreign import ccall safe "sys/socket.h send"-  c_safe_addr_send :: Fd -> Addr# -> CSize -> MessageFlags 'Send -> IO CSsize-foreign import ccall safe "sys/socket.h send_offset"-  c_safe_bytearray_send :: Fd -> ByteArray# -> Int -> CSize -> MessageFlags 'Send -> IO CSsize-foreign import ccall safe "sys/socket.h send_offset"-  c_safe_mutablebytearray_send :: Fd -> MutableByteArray# RealWorld -> Int -> CSize -> MessageFlags 'Send -> IO CSsize-foreign import ccall safe "sys/socket.h send"-  c_safe_mutablebytearray_no_offset_send :: Fd -> MutableByteArray# RealWorld -> CSize -> MessageFlags 'Send -> IO CSsize-foreign import ccall unsafe "sys/socket.h send"-  c_unsafe_addr_send :: Fd -> Addr# -> CSize -> MessageFlags 'Send -> IO CSsize-foreign import ccall unsafe "sys/socket.h send_offset"-  c_unsafe_bytearray_send :: Fd -> ByteArray# -> Int -> CSize -> MessageFlags 'Send -> IO CSsize-foreign import ccall unsafe "sys/socket.h send_offset"-  c_unsafe_mutable_bytearray_send :: Fd -> MutableByteArray# RealWorld -> Int -> CSize -> MessageFlags 'Send -> IO CSsize---- The ByteArray# (second to last argument) is a SocketAddress.-foreign import ccall unsafe "sys/socket.h sendto_offset"-  c_unsafe_bytearray_sendto :: Fd -> ByteArray# -> Int -> CSize -> MessageFlags 'Send -> ByteArray# -> CInt -> IO CSsize--- The ByteArray# (second to last argument) is a SocketAddress.-foreign import ccall unsafe "sys/socket.h sendto_offset"-  c_unsafe_mutable_bytearray_sendto :: Fd -> MutableByteArray# RealWorld -> Int -> CSize -> MessageFlags 'Send -> ByteArray# -> CInt -> IO CSsize-foreign import ccall unsafe "sys/socket.h sendto_inet_offset"-  c_unsafe_mutable_bytearray_sendto_inet :: Fd -> MutableByteArray# RealWorld -> Int -> CSize -> MessageFlags 'Send -> Word16 -> Word32 -> IO CSsize-foreign import ccall unsafe "HaskellPosix.h sendto_inet_offset"-  c_unsafe_bytearray_sendto_inet :: Fd -> ByteArray# -> Int -> CSize -> MessageFlags 'Send -> Word16 -> Word32 -> IO CSsize-foreign import ccall unsafe "HaskellPosix.h sendto_inet_addr"-  c_unsafe_addr_sendto_inet :: Fd -> Addr# -> CSize -> MessageFlags 'Send -> Word16 -> Word32 -> IO CSsize--foreign import ccall unsafe "HaskellPosix.h sendmsg_a"-  c_unsafe_sendmsg_a :: Fd -> Addr# -> CSize -> MutableByteArray# RealWorld -> Int -> CSize -> MessageFlags 'Send -> IO CSsize--foreign import ccall unsafe "HaskellPosix.h sendmsg_b"-  c_unsafe_sendmsg_b :: Fd -> MutableByteArray# RealWorld -> Int -> CSize -> Addr# -> CSize -> MessageFlags 'Send -> IO CSsize--#if defined(UNLIFTEDARRAYFUNCTIONS)-foreign import ccall unsafe "HaskellPosix.h sendmsg_bytearrays"-  c_unsafe_sendmsg_bytearrays :: Fd -> UnliftedArray# ByteArray# -> Int -> Int -> Int -> MessageFlags 'Send -> IO CSsize-#endif--foreign import ccall safe "sys/uio.h writev"-  c_safe_writev :: Fd -> MutableByteArray# RealWorld -> CInt -> IO CSsize---- There are several ways to wrap recv.-foreign import ccall safe "sys/socket.h recv"-  c_safe_addr_recv :: Fd -> Addr# -> CSize -> MessageFlags 'Receive -> IO CSsize-foreign import ccall unsafe "sys/socket.h recv"-  c_unsafe_addr_recv :: Fd -> Addr# -> CSize -> MessageFlags 'Receive -> IO CSsize-foreign import ccall unsafe "sys/socket.h recv_offset"-  c_unsafe_mutable_byte_array_recv :: Fd -> MutableByteArray# RealWorld -> Int -> CSize -> MessageFlags 'Receive -> IO CSsize---- The last two arguments are SocketAddress and Ptr CInt.-foreign import ccall unsafe "sys/socket.h recvfrom_offset"-  c_unsafe_mutable_byte_array_recvfrom :: Fd -> MutableByteArray# RealWorld -> Int -> CSize -> MessageFlags 'Receive -> MutableByteArray# RealWorld -> MutableByteArray# RealWorld -> IO CSsize-foreign import ccall unsafe "sys/socket.h recvfrom_offset_peerless"-  c_unsafe_mutable_byte_array_peerless_recvfrom ::-       Fd-    -> MutableByteArray# RealWorld -> Int -> CSize-    -> MessageFlags 'Receive -> IO CSsize-foreign import ccall unsafe "sys/socket.h recvfrom_addr_peerless"-  c_unsafe_addr_peerless_recvfrom ::-       Fd -> Addr# -> CSize -> MessageFlags 'Receive -> IO CSsize-foreign import ccall unsafe "sys/socket.h recvfrom_offset_inet"-  c_unsafe_recvfrom_inet ::-       Fd-    -> MutableByteArray# RealWorld-    -> Int-    -> CSize-    -> MessageFlags 'Receive-    -> MutableByteArray# RealWorld-    -> Int-    -> IO CSsize-foreign import ccall unsafe "sys/socket.h recvfrom_offset_inet_addr"-  c_unsafe_recvfrom_inet_addr ::-       Fd-    -> Addr#-    -> CSize-    -> MessageFlags 'Receive-    -> MutableByteArray# RealWorld-    -> Int-    -> IO CSsize--foreign import ccall unsafe "sys/socket.h recvmsg"-  c_unsafe_addr_recvmsg :: Fd-                        -> Addr# -- This addr is a pointer to msghdr-                        -> MessageFlags 'Receive-                        -> IO CSsize---- | Create an endpoint for communication, returning a file---   descriptor that refers to that endpoint. The---   <http://pubs.opengroup.org/onlinepubs/9699919799/functions/socket.html POSIX specification>---   includes more details. No special preparation is required before calling---   this function. The author believes that it cannot block for a prolonged---   period of time.-uninterruptibleSocket ::-     Family -- ^ Communications domain (e.g. 'internet', 'unix')-  -> Type -- ^ Socket type (e.g. 'datagram', 'stream') with flags-  -> Protocol -- ^ Protocol-  -> IO (Either Errno Fd)-uninterruptibleSocket dom typ prot = c_socket dom typ prot >>= errorsFromFd---- | Create an unbound pair of connected sockets in a specified domain, of---   a specified type, under the protocol optionally specified by the protocol---   argument. The <http://pubs.opengroup.org/onlinepubs/9699919799/functions/socketpair.html POSIX specification>---   includes more details. No special preparation is required before calling---   this function. The author believes that it cannot block for a prolonged---   period of time.-uninterruptibleSocketPair ::-     Family -- ^ Communications domain (probably 'unix')-  -> Type -- ^ Socket type (e.g. 'datagram', 'stream') with flags-  -> Protocol -- ^ Protocol-  -> IO (Either Errno (Fd,Fd))-uninterruptibleSocketPair dom typ prot = do-  -- If this ever switches to the safe FFI, we will need to use-  -- a pinned array here instead.-  (sockets@(MutablePrimArray sockets#) :: MutablePrimArray RealWorld Fd) <- PM.newPrimArray 2-  r <- c_socketpair dom typ prot sockets#-  if r == 0-    then do-      fd1 <- PM.readPrimArray sockets 0-      fd2 <- PM.readPrimArray sockets 1-      pure (Right (fd1,fd2))-    else fmap Left getErrno----- | Given node and service, which identify an Internet host and a service,--- @getaddrinfo()@ returns one or more @addrinfo@ structures. The type of this--- wrapper differs slightly from the type of its C counterpart. Remember to call--- 'uninterruptibleFreeAddressInfo' when finished with the result.-getAddressInfo ::-     CString -- ^ Node, identifies an Internet host-  -> CString -- ^ Service-  -> Ptr AddressInfo -- ^ Hints-  -> IO (Either Errno (Ptr AddressInfo))-getAddressInfo !node !service !hints = do-  resBuf@(MutableByteArray resBuf#) <- PM.newPinnedByteArray (PM.sizeOf (undefined :: Ptr ()))-  c_safe_getaddrinfo node service hints resBuf# >>= \case-    Errno 0 -> do-      res <- PM.readByteArray resBuf 0-      pure (Right res)-    e -> pure (Left e)---- | Assign a local socket address address to a socket identified by---   descriptor socket that has no local socket address assigned. The---   <http://pubs.opengroup.org/onlinepubs/9699919799/functions/bind.html POSIX specification>---   includes more details. The 'SocketAddress' represents the @sockaddr@ pointer argument, together---   with its @socklen_t@ size, as a byte array. This allows @bind@ to---   be used with @sockaddr@ extensions on various platforms. No special---   preparation is required before calling this function. The author---   believes that it cannot block for a prolonged period of time.-uninterruptibleBind ::-     Fd -- ^ Socket-  -> SocketAddress -- ^ Socket address, extensible tagged union-  -> IO (Either Errno ())-uninterruptibleBind fd (SocketAddress b@(ByteArray b#)) =-  c_bind fd b# (intToCInt (PM.sizeofByteArray b)) >>= errorsFromInt_---- | Mark the socket as a passive socket, that is, as a socket that---   will be used to accept incoming connection requests using @accept@.---   The <http://pubs.opengroup.org/onlinepubs/9699919799/functions/listen.html POSIX specification>---   includes more details. No special preparation is required before---   calling this function. The author believes that it cannot block---   for a prolonged period of time.-uninterruptibleListen ::-     Fd -- ^ Socket-  -> CInt -- ^ Backlog-  -> IO (Either Errno ())-uninterruptibleListen fd backlog = c_listen fd backlog >>= errorsFromInt_---- | Connect the socket to the specified socket address.---   The <http://pubs.opengroup.org/onlinepubs/9699919799/functions/connect.html POSIX specification>---   includes more details.-connect ::-     Fd -- ^ Fd-  -> SocketAddress -- ^ Socket address, extensible tagged union-  -> IO (Either Errno ())-connect fd (SocketAddress sockAddr@(ByteArray sockAddr#)) =-  case isByteArrayPinned sockAddr of-    True -> c_safe_connect fd sockAddr# (intToCInt (PM.sizeofByteArray sockAddr)) >>= errorsFromInt_-    False -> do-      let len = PM.sizeofByteArray sockAddr-      x@(MutableByteArray x#) <- PM.newPinnedByteArray len-      PM.copyByteArray x 0 sockAddr 0 len-      c_safe_mutablebytearray_connect fd x# (intToCInt len) >>= errorsFromInt_---- | Connect the socket to the specified socket address.---   The <http://pubs.opengroup.org/onlinepubs/9699919799/functions/connect.html POSIX specification>---   includes more details. The only sensible way to use this is to---   give a nonblocking socket as the argument.-uninterruptibleConnect ::-     Fd -- ^ Fd-  -> SocketAddress -- ^ Socket address, extensible tagged union-  -> IO (Either Errno ())-uninterruptibleConnect fd (SocketAddress sockAddr@(ByteArray sockAddr#)) =-  c_unsafe_connect fd sockAddr# (intToCInt (PM.sizeofByteArray sockAddr)) >>= errorsFromInt_--uninterruptibleConnectPtr ::-     Fd -- ^ Fd-  -> Ptr a -- ^ Socket address-  -> Int -- ^ Size of socket address-  -> IO (Either Errno ())-uninterruptibleConnectPtr !fd (Ptr sockAddr#) !sz =-  c_unsafe_connect_addr fd sockAddr# (intToCInt sz) >>= errorsFromInt_---- | Extract the first connection on the queue of pending connections. The---   <http://pubs.opengroup.org/onlinepubs/9699919799/functions/accept.html POSIX specification>---   includes more details. This function\'s type differs slightly from---   the specification:------   > int accept(int socket, struct sockaddr *restrict address, socklen_t *restrict address_len);------   Instead of requiring the caller to prepare buffers through which---   information is returned, this haskell binding to @accept@ prepares---   those buffers internally. This eschews C\'s characteristic buffer-passing---   in favor of the Haskell convention of allocating internally and returning.------   More specifically, this binding lacks an argument corresponding to the---   @sockaddr@ buffer from the specification. That mutable buffer is allocated---   internally, resized and frozen upon a success, and returned along with---   the file descriptor of the accepted socket. The size of this buffer is---   determined by the second argument (maximum socket address size). This---   size argument is also writen to the @address_len@ buffer, which is also---   allocated internally. The size returned through this pointer is used to---   resize the @sockaddr@ buffer, which is then frozen so that an immutable---   'SocketAddress' is returned to the end user.------   For applications uninterested in the peer (described by @sockaddr@),---   POSIX @accept@ allows the null pointer to be passed as both @address@ and---   @address_len@. This behavior is provided by 'accept_'.-accept ::-     Fd -- ^ Listening socket-  -> CInt -- ^ Maximum socket address size-  -> IO (Either Errno (CInt,SocketAddress,Fd)) -- ^ Peer information and connected socket-accept !sock !maxSz = do-  sockAddrBuf@(MutableByteArray sockAddrBuf#) <- PM.newPinnedByteArray (cintToInt maxSz)-  lenBuf@(MutableByteArray lenBuf#) <- PM.newPinnedByteArray (PM.sizeOf (undefined :: CInt))-  PM.writeByteArray lenBuf 0 maxSz-  r <- c_safe_accept sock sockAddrBuf# lenBuf#-  if r > (-1)-    then do-      (sz :: CInt) <- PM.readByteArray lenBuf 0-      -- Why copy when we could just shrink? We want to always return-      -- byte arrays that are not explicitly pinned.-      let minSz = min sz maxSz-      x <- PM.newByteArray (cintToInt minSz)-      PM.copyMutableByteArray x 0 sockAddrBuf 0 (cintToInt minSz)-      sockAddr <- PM.unsafeFreezeByteArray x-      pure (Right (sz,SocketAddress sockAddr,r))-    else fmap Left getErrno---- | See 'accept'. This uses the unsafe FFI. Consequently, it does not---   not need to allocate pinned memory. It only makes sense to call this---   on a nonblocking socket.-uninterruptibleAccept ::-     Fd -- ^ Listening socket-  -> CInt -- ^ Maximum socket address size-  -> IO (Either Errno (CInt,SocketAddress,Fd)) -- ^ Peer information and connected socket-uninterruptibleAccept !sock !maxSz = do-  sockAddrBuf@(MutableByteArray sockAddrBuf#) <- PM.newByteArray (cintToInt maxSz)-  lenBuf@(MutableByteArray lenBuf#) <- PM.newByteArray (PM.sizeOf (undefined :: CInt))-  PM.writeByteArray lenBuf 0 maxSz-  r <- c_unsafe_accept sock sockAddrBuf# lenBuf#-  if r > (-1)-    then do-      (sz :: CInt) <- PM.readByteArray lenBuf 0-      if sz < maxSz-        then shrinkMutableByteArray sockAddrBuf (cintToInt sz)-        else pure ()-      sockAddr <- PM.unsafeFreezeByteArray sockAddrBuf-      pure (Right (sz,SocketAddress sockAddr,r))-    else fmap Left getErrno---- | A variant of 'accept' that does not provide the user with a---   'SocketAddress' detailing the peer.-accept_ ::-     Fd -- ^ Listening socket-  -> IO (Either Errno Fd) -- ^ Connected socket-accept_ sock =-  c_safe_ptr_accept sock nullPtr nullPtr >>= errorsFromFd---- | Retrieve the locally-bound name of the specified socket. The---   <http://pubs.opengroup.org/onlinepubs/9699919799/functions/accept.html POSIX specification>---   of @getsockname@ includes more details.-uninterruptibleGetSocketName ::-     Fd -- ^ Socket-  -> CInt -- ^ Maximum socket address size-  -> IO (Either Errno (CInt,SocketAddress))-uninterruptibleGetSocketName sock maxSz = do-  sockAddrBuf@(MutableByteArray sockAddrBuf#) <- PM.newByteArray (cintToInt maxSz)-  lenBuf@(MutableByteArray lenBuf#) <- PM.newByteArray (PM.sizeOf (undefined :: CInt))-  PM.writeByteArray lenBuf 0 maxSz-  r <- c_unsafe_getsockname sock sockAddrBuf# lenBuf#-  if r == 0-    then do-      (sz :: CInt) <- PM.readByteArray lenBuf 0-      if sz < maxSz-        then shrinkMutableByteArray sockAddrBuf (cintToInt sz)-        else pure ()-      sockAddr <- PM.unsafeFreezeByteArray sockAddrBuf-      pure (Right (sz,SocketAddress sockAddr))-    else fmap Left getErrno---- | Retrieve the value for the option specified by the 'Option' argument for---   the socket specified by the 'Fd' argument. The---   <http://pubs.opengroup.org/onlinepubs/9699919799/functions/getsockopt.html POSIX specification>---   of @getsockopt@ includes more details.-uninterruptibleGetSocketOption ::-     Fd -- ^ Socket-  -> Level -- ^ Socket level-  -> OptionName -- Option name-  -> CInt -- ^ Maximum option value size-  -> IO (Either Errno (CInt,OptionValue))-uninterruptibleGetSocketOption sock level optName maxSz = do-  valueBuf@(MutableByteArray valueBuf#) <- PM.newByteArray (cintToInt maxSz)-  lenBuf@(MutableByteArray lenBuf#) <- PM.newByteArray (PM.sizeOf (undefined :: CInt))-  PM.writeByteArray lenBuf 0 maxSz-  r <- c_unsafe_getsockopt sock level optName valueBuf# lenBuf#-  if r == 0-    then do-      (sz :: CInt) <- PM.readByteArray lenBuf 0-      if sz < maxSz-        then shrinkMutableByteArray valueBuf (cintToInt sz)-        else pure ()-      value <- PM.unsafeFreezeByteArray valueBuf-      pure (Right (sz,OptionValue value))-    else fmap Left getErrno---- | Set the value for the option specified by the 'Option' argument for---   the socket specified by the 'Fd' argument. The---   <http://pubs.opengroup.org/onlinepubs/9699919799/functions/getsockopt.html POSIX specification>---   of @getsockopt@ includes more details. This variant requires that the---   size of the @option_value@---   be the same as the size of 'CInt'. That is, the @option_name@ must---   describe an option that is represented by a C integer. This is a---   common case, so we avoid allocations by reference-passing in C.-uninterruptibleSetSocketOptionInt ::-     Fd -- ^ Socket-  -> Level -- ^ Socket level-  -> OptionName -- ^ Option name-  -> CInt -- ^ Option value-  -> IO (Either Errno ())-uninterruptibleSetSocketOptionInt sock level optName optValue =-  c_unsafe_setsockopt_int sock level optName optValue >>= errorsFromInt_---- | Set the value for the option specified by the 'Option' argument for---   the socket specified by the 'Fd' argument. The---   <http://pubs.opengroup.org/onlinepubs/9699919799/functions/getsockopt.html POSIX specification>---   of @getsockopt@ includes more details.-uninterruptibleSetSocketOption ::-     Fd -- ^ Socket-  -> Level -- ^ Socket level-  -> OptionName -- ^ Option name-  -> Ptr Void -- ^ Option value-  -> CInt -- ^ Option value length-  -> IO (Either Errno ())-uninterruptibleSetSocketOption sock level optName optValue optLen =-  c_unsafe_setsockopt sock level optName optValue optLen >>= errorsFromInt_---- | Variant of 'uninterruptibleSetSocketOption' that accepts the option---   as a byte array instead of a pointer into unmanaged memory. The argument---   does not need to be pinned.-uninterruptibleSetSocketOptionByteArray ::-     Fd -- ^ Socket-  -> Level -- ^ Socket level-  -> OptionName -- ^ Option name-  -> ByteArray -- ^ Option value-  -> CInt -- ^ Option value length-  -> IO (Either Errno ())-uninterruptibleSetSocketOptionByteArray sock level optName (ByteArray optVal) optLen =-  c_unsafe_setsockopt_ba sock level optName optVal optLen >>= errorsFromInt_---- | Send data from a byte array over a network socket. Users---   may specify an offset and a length to send fewer bytes than are---   actually present in the array. Since this uses the safe---   FFI, it allocates a pinned copy of the bytearry if it was not---   already pinned.-sendByteArray ::-     Fd -- ^ Socket-  -> ByteArray -- ^ Source byte array-  -> Int -- ^ Offset into source array-  -> CSize -- ^ Length in bytes-  -> MessageFlags 'Send -- ^ Flags-  -> IO (Either Errno CSize) -- ^ Number of bytes pushed to send buffer-sendByteArray fd b@(ByteArray b#) off len flags = if isByteArrayPinned b-  then errorsFromSize =<< c_safe_bytearray_send fd b# off len flags-  else do-    x@(MutableByteArray x#) <- PM.newPinnedByteArray (csizeToInt len)-    PM.copyByteArray x off b 0 (csizeToInt len)-    errorsFromSize =<< c_safe_mutablebytearray_no_offset_send fd x# len flags--#if MIN_VERSION_base(4,16,0)-data UList (a :: TYPE ('BoxedRep 'Unlifted)) where-#else-data UList (a :: TYPE 'UnliftedRep) where-#endif-  UNil :: UList a-  UCons :: a -> UList a -> UList a---- Internal function. Fold with strict accumulator. Upper bound is exclusive.--- Hits every int in the range [0,hi) from highest to lowest.-foldDownward :: forall a. Int -> a -> (a -> Int -> IO a) -> IO a-{-# INLINE foldDownward #-}-foldDownward !hi !a0 f = go (hi - 1) a0 where-  go :: Int -> a -> IO a-  go !ix !a = if ix >= 0-    then f a ix >>= go (ix - 1)-    else pure a---- | Copy and pin a byte array if, it's not already pinned.-pinByteArray :: ByteArray -> IO (Maybe ByteArray)-{-# INLINE pinByteArray #-}-pinByteArray byteArray =-  if isByteArrayPinned byteArray-    then-      pure Nothing-    else do-      pinnedByteArray <- PM.newPinnedByteArray len-      PM.copyByteArray pinnedByteArray 0 byteArray 0 len-      r <- PM.unsafeFreezeByteArray pinnedByteArray-      pure (Just r)-  where-    len = PM.sizeofByteArray byteArray---- | Send two payloads (one from unmanaged memory and one from--- managed memory) over a network socket.-uninterruptibleSendMessageA ::-     Fd -- ^ Socket-  -> Addr -- ^ Source address (payload A)-  -> CSize -- ^ Length in bytes (payload A)-  -> MutableByteArrayOffset RealWorld -- ^ Source and offset (payload B)-  -> CSize -- ^ Length in bytes (payload B)-  -> MessageFlags 'Send -- ^ Flags-  -> IO (Either Errno CSize) -- ^ Number of bytes pushed to send buffer-uninterruptibleSendMessageA fd (Addr addr) lenA-  (MutableByteArrayOffset{array,offset}) lenB flags =-    c_unsafe_sendmsg_a fd addr lenA (unMba array) offset lenB flags-      >>= errorsFromSize---- | Send two payloads (one from managed memory and one from--- unmanaged memory) over a network socket.-uninterruptibleSendMessageB ::-     Fd -- ^ Socket-  -> MutableByteArrayOffset RealWorld -- ^ Source and offset (payload B)-  -> CSize -- ^ Length in bytes (payload B)-  -> Addr -- ^ Source address (payload A)-  -> CSize -- ^ Length in bytes (payload A)-  -> MessageFlags 'Send -- ^ Flags-  -> IO (Either Errno CSize) -- ^ Number of bytes pushed to send buffer-uninterruptibleSendMessageB fd -  (MutableByteArrayOffset{array,offset}) lenB-  (Addr addr) lenA flags =-    c_unsafe_sendmsg_b fd (unMba array) offset lenB addr lenA flags-      >>= errorsFromSize---- | Send data from a mutable byte array over a network socket. Users---   may specify an offset and a length to send fewer bytes than are---   actually present in the array. Since this uses the safe---   FFI, it allocates a pinned copy of the bytearry if it was not---   already pinned.-sendMutableByteArray ::-     Fd -- ^ Socket-  -> MutableByteArray RealWorld -- ^ Source byte array-  -> Int -- ^ Offset into source array-  -> CSize -- ^ Length in bytes-  -> MessageFlags 'Send -- ^ Flags-  -> IO (Either Errno CSize) -- ^ Number of bytes pushed to send buffer-sendMutableByteArray fd b@(MutableByteArray b#) off len flags = if isMutableByteArrayPinned b-  then errorsFromSize =<< c_safe_mutablebytearray_send fd b# off len flags-  else do-    x@(MutableByteArray x#) <- PM.newPinnedByteArray (csizeToInt len)-    PM.copyMutableByteArray x off b 0 (csizeToInt len)-    errorsFromSize =<< c_safe_mutablebytearray_no_offset_send fd x# len flags---- | Send data from an address over a network socket. This is not guaranteed---   to send the entire length. This uses the safe FFI since---   it may block indefinitely.-send ::-     Fd -- ^ Connected socket-  -> Addr -- ^ Source address-  -> CSize -- ^ Length in bytes-  -> MessageFlags 'Send -- ^ Flags-  -> IO (Either Errno CSize) -- ^ Number of bytes pushed to send buffer-send fd (Addr addr) len flags =-  c_safe_addr_send fd addr len flags >>= errorsFromSize---- | Send data from an address over a network socket. This uses the unsafe FFI.---   Users of this function should be sure to set flags that prohibit this---   from blocking. On Linux this is accomplished with @O_NONBLOCK@. It is---   often desirable to call 'threadWaitWrite' on a nonblocking socket before---   calling @unsafeSend@ on it.-uninterruptibleSend ::-     Fd -- ^ Socket-  -> Addr -- ^ Source address-  -> CSize -- ^ Length in bytes-  -> MessageFlags 'Send -- ^ Flags-  -> IO (Either Errno CSize) -- ^ Number of bytes pushed to send buffer-uninterruptibleSend fd (Addr addr) len flags =-  c_unsafe_addr_send fd addr len flags >>= errorsFromSize---- | Send data from a byte array over a network socket. This uses the unsafe FFI;---   considerations pertaining to 'sendUnsafe' apply to this function as well. Users---   may specify a length to send fewer bytes than are actually present in the---   array.-uninterruptibleSendByteArray ::-     Fd -- ^ Socket-  -> ByteArray -- ^ Source byte array-  -> Int -- ^ Offset into source array-  -> CSize -- ^ Length in bytes-  -> MessageFlags 'Send -- ^ Flags-  -> IO (Either Errno CSize) -- ^ Number of bytes pushed to send buffer-uninterruptibleSendByteArray fd (ByteArray b) off len flags =-  c_unsafe_bytearray_send fd b off len flags >>= errorsFromSize---- | Send data from a mutable byte array over a network socket. This uses the unsafe FFI;---   considerations pertaining to 'sendUnsafe' apply to this function as well. Users---   specify an offset and a length to send fewer bytes than are actually present in the---   array.-uninterruptibleSendMutableByteArray ::-     Fd -- ^ Socket-  -> MutableByteArray RealWorld -- ^ Source mutable byte array-  -> Int -- ^ Offset into source array-  -> CSize -- ^ Length in bytes-  -> MessageFlags 'Send -- ^ Flags-  -> IO (Either Errno CSize) -- ^ Number of bytes pushed to send buffer-uninterruptibleSendMutableByteArray fd (MutableByteArray b) off len flags =-  c_unsafe_mutable_bytearray_send fd b off len flags >>= errorsFromSize---- | Send data from a byte array over an unconnected network socket.---   This uses the unsafe FFI; considerations pertaining to 'sendToUnsafe'---   apply to this function as well. The offset and length arguments---   cause a slice of the byte array to be sent rather than the entire---   byte array.-uninterruptibleSendToByteArray ::-     Fd -- ^ Socket-  -> ByteArray -- ^ Source byte array-  -> Int -- ^ Offset into source array-  -> CSize -- ^ Length in bytes-  -> MessageFlags 'Send -- ^ Flags-  -> SocketAddress -- ^ Socket Address-  -> IO (Either Errno CSize) -- ^ Number of bytes pushed to send buffer-uninterruptibleSendToByteArray fd (ByteArray b) off len flags (SocketAddress a@(ByteArray a#)) =-  c_unsafe_bytearray_sendto fd b off len flags a# (intToCInt (PM.sizeofByteArray a)) >>= errorsFromSize---- | Variant of 'uninterruptibleSendToByteArray' that requires---   that @sockaddr_in@ be used as the socket address. This is used to---   avoid allocating a buffer for the socket address when the caller---   knows in advance that they are sending to an IPv4 address.-uninterruptibleSendToInternetByteArray ::-     Fd -- ^ Socket-  -> ByteArray -- ^ Source byte array-  -> Int -- ^ Offset into source array-  -> CSize -- ^ Length in bytes-  -> MessageFlags 'Send -- ^ Flags-  -> SocketAddressInternet -- ^ Socket Address-  -> IO (Either Errno CSize) -- ^ Number of bytes pushed to send buffer-uninterruptibleSendToInternetByteArray fd (ByteArray b) off len flags (SocketAddressInternet{port,address}) =-  c_unsafe_bytearray_sendto_inet fd b off len flags port address >>= errorsFromSize---- | Variant of 'uninterruptibleSendToByteArray' that requires---   that @sockaddr_in@ be used as the socket address. This is used to---   avoid allocating a buffer for the socket address when the caller---   knows in advance that they are sending to an IPv4 address.-uninterruptibleSendToInternet ::-     Fd -- ^ Socket-  -> Addr -- ^ Source byte array-  -> CSize -- ^ Length in bytes-  -> MessageFlags 'Send -- ^ Flags-  -> SocketAddressInternet -- ^ Socket Address-  -> IO (Either Errno CSize) -- ^ Number of bytes pushed to send buffer-uninterruptibleSendToInternet fd (Addr b) len flags (SocketAddressInternet{port,address}) =-  c_unsafe_addr_sendto_inet fd b len flags port address >>= errorsFromSize---- | Send data from a mutable byte array over an unconnected network socket.---   This uses the unsafe FFI; concerns pertaining to 'uninterruptibleSend'---   apply to this function as well. The offset and length arguments---   cause a slice of the mutable byte array to be sent rather than the entire---   byte array.-uninterruptibleSendToMutableByteArray ::-     Fd -- ^ Socket-  -> MutableByteArray RealWorld -- ^ Source byte array-  -> Int -- ^ Offset into source array-  -> CSize -- ^ Length in bytes-  -> MessageFlags 'Send -- ^ Flags-  -> SocketAddress -- ^ Socket Address-  -> IO (Either Errno CSize) -- ^ Number of bytes pushed to send buffer-uninterruptibleSendToMutableByteArray fd (MutableByteArray b) off len flags (SocketAddress a@(ByteArray a#)) =-  c_unsafe_mutable_bytearray_sendto fd b off len flags a# (intToCInt (PM.sizeofByteArray a)) >>= errorsFromSize---- | Variant of 'uninterruptibleSendToMutableByteArray' that requires---   that @sockaddr_in@ be used as the socket address. This is used to---   avoid allocating a buffer for the socket address when the caller---   knows in advance that they are sending to an IPv4 address.-uninterruptibleSendToInternetMutableByteArray ::-     Fd -- ^ Socket-  -> MutableByteArray RealWorld -- ^ Source byte array-  -> Int -- ^ Offset into source array-  -> CSize -- ^ Length in bytes-  -> MessageFlags 'Send -- ^ Flags-  -> SocketAddressInternet -- ^ Socket Address-  -> IO (Either Errno CSize) -- ^ Number of bytes pushed to send buffer-uninterruptibleSendToInternetMutableByteArray fd (MutableByteArray b) off len flags (SocketAddressInternet{port,address}) =-  c_unsafe_mutable_bytearray_sendto_inet fd b off len flags port address >>= errorsFromSize---- | Receive data into an address from a network socket. This wraps @recv@ using---   the safe FFI. When the returned size is zero, there are no---   additional bytes to receive and the peer has performed an orderly shutdown.-receive ::-     Fd -- ^ Socket-  -> Addr -- ^ Source address-  -> CSize -- ^ Length in bytes-  -> MessageFlags 'Receive -- ^ Flags-  -> IO (Either Errno CSize)-receive fd (Addr addr) len flags =-  c_safe_addr_recv fd addr len flags >>= errorsFromSize---- | Receive data into a byte array from a network socket. This wraps @recv@ using---   the safe FFI. When the returned size is zero, there are no---   additional bytes to receive and the peer has performed an orderly shutdown.-receiveByteArray ::-     Fd -- ^ Socket-  -> CSize -- ^ Length in bytes-  -> MessageFlags 'Receive -- ^ Flags-  -> IO (Either Errno ByteArray)-receiveByteArray !fd !len !flags = do-  m <- PM.newPinnedByteArray (csizeToInt len)-  let !(Addr addr) = ptrToAddr (PM.mutableByteArrayContents m)-  r <- c_safe_addr_recv fd addr len flags-  if r /= (-1)-    then do-      -- Why copy when we could just shrink? We want to always return-      -- byte arrays that are not explicitly pinned.-      let sz = cssizeToInt r-      x <- PM.newByteArray sz-      PM.copyMutableByteArray x 0 m 0 sz-      a <- PM.unsafeFreezeByteArray x-      pure (Right a)-    else fmap Left getErrno---- | Receive data into an address from a network socket. This wraps @recv@---   using the unsafe FFI. Users of this function should be sure to set flags---   that prohibit this from blocking. On Linux this is accomplished by setting---   the @MSG_DONTWAIT@ flag and handling the resulting @EAGAIN@ or---   @EWOULDBLOCK@. When the returned size is zero, there are no additional---   bytes to receive and the peer has performed an orderly shutdown.-uninterruptibleReceive ::-     Fd -- ^ Socket-  -> Addr -- ^ Source address-  -> CSize -- ^ Length in bytes-  -> MessageFlags 'Receive -- ^ Flags-  -> IO (Either Errno CSize)-{-# inline uninterruptibleReceive #-}-uninterruptibleReceive !fd (Addr !addr) !len !flags =-  c_unsafe_addr_recv fd addr len flags >>= errorsFromSize---- | Receive data into an address from a network socket. This uses the unsafe---   FFI; considerations pertaining to 'receiveUnsafe' apply to this function---   as well. Users may specify a length to receive fewer bytes than are---   actually present in the mutable byte array.-uninterruptibleReceiveMutableByteArray ::-     Fd -- ^ Socket-  -> MutableByteArray RealWorld -- ^ Destination byte array-  -> Int -- ^ Destination offset-  -> CSize -- ^ Maximum bytes to receive-  -> MessageFlags 'Receive -- ^ Flags-  -> IO (Either Errno CSize) -- ^ Bytes received into array-{-# inline uninterruptibleReceiveMutableByteArray #-}-uninterruptibleReceiveMutableByteArray !fd (MutableByteArray !b) !off !len !flags =-  c_unsafe_mutable_byte_array_recv fd b off len flags >>= errorsFromSize---- | Receive data into an address from an unconnected network socket. This---   uses the unsafe FFI. Users may specify an offset into the destination---   byte array. This function does not resize the buffer.-uninterruptibleReceiveFromMutableByteArray ::-     Fd -- ^ Socket-  -> MutableByteArray RealWorld -- ^ Destination byte array-  -> Int -- ^ Destination offset-  -> CSize -- ^ Maximum bytes to receive-  -> MessageFlags 'Receive -- ^ Flags-  -> CInt -- ^ Maximum socket address size-  -> IO (Either Errno (CInt,SocketAddress,CSize))-     -- ^ Remote host, bytes received into array, bytes needed for @addrlen@.-{-# inline uninterruptibleReceiveFromMutableByteArray #-}--- GHC does not inline this unless we give it the pragma. We really--- want this to inline since inlining typically avoids the Left/Right--- data constructor allocation.-uninterruptibleReceiveFromMutableByteArray !fd (MutableByteArray !b) !off !len !flags !maxSz = do-  -- TODO: We currently allocate one buffer for the size and-  -- one for the peer. We could improve this by allocating-  -- a single buffer instead. We would need to add some-  -- cleverness in the cbits directory.-  sockAddrBuf@(MutableByteArray sockAddrBuf#) <- PM.newByteArray (cintToInt maxSz)-  lenBuf@(MutableByteArray lenBuf#) <- PM.newByteArray (PM.sizeOf (undefined :: CInt))-  PM.writeByteArray lenBuf 0 maxSz-  r <- c_unsafe_mutable_byte_array_recvfrom fd b off len flags sockAddrBuf# lenBuf#-  if r > (-1)-    then do-      (sz :: CInt) <- PM.readByteArray lenBuf 0-      if sz < maxSz-        then shrinkMutableByteArray sockAddrBuf (cintToInt sz)-        else pure ()-      sockAddr <- PM.unsafeFreezeByteArray sockAddrBuf-      pure (Right (sz,SocketAddress sockAddr,cssizeToCSize r))-    else fmap Left getErrno--uninterruptibleReceiveFromInternet ::-     Fd -- ^ Socket-  -> Addr -- ^ Destination byte array-  -> CSize -- ^ Maximum bytes to receive-  -> MessageFlags 'Receive -- ^ Flags-  -> MutablePrimArrayOffset RealWorld SocketAddressInternet -- ^ Address-  -> IO (Either Errno CSize) -- ^ Number of bytes received into array-{-# inline uninterruptibleReceiveFromInternet #-}-uninterruptibleReceiveFromInternet !fd-  (Addr b) !len !flags-  (MutablePrimArrayOffset (MutablePrimArray sockAddrBuf) addrOff) =-    c_unsafe_recvfrom_inet_addr fd b len flags sockAddrBuf addrOff-    >>= errorsFromSize--uninterruptibleReceiveFromInternetMutableByteArray ::-     Fd -- ^ Socket-  -> MutableByteArrayOffset RealWorld -- ^ Destination byte array-  -> CSize -- ^ Maximum bytes to receive-  -> MessageFlags 'Receive -- ^ Flags-  -> MutablePrimArrayOffset RealWorld SocketAddressInternet -- ^ Address-  -> IO (Either Errno CSize) -- ^ Number of bytes received into array-{-# inline uninterruptibleReceiveFromInternetMutableByteArray #-}-uninterruptibleReceiveFromInternetMutableByteArray !fd-  (MutableByteArrayOffset (MutableByteArray b) off) !len !flags-  (MutablePrimArrayOffset (MutablePrimArray sockAddrBuf) addrOff) =-    c_unsafe_recvfrom_inet fd b off len flags sockAddrBuf addrOff-    >>= errorsFromSize---- | Receive data into an address from a network socket. This uses the unsafe---   FFI. This does not return the socket address of the remote host that---   sent the packet received.-uninterruptibleReceiveFromMutableByteArray_ ::-     Fd -- ^ Socket-  -> MutableByteArray RealWorld -- ^ Destination byte array-  -> Int -- ^ Destination offset-  -> CSize -- ^ Maximum bytes to receive-  -> MessageFlags 'Receive -- ^ Flags-  -> IO (Either Errno CSize) -- ^ Number of bytes received into array-{-# inline uninterruptibleReceiveFromMutableByteArray_ #-}-uninterruptibleReceiveFromMutableByteArray_ !fd (MutableByteArray !b) !off !len !flags =-  c_unsafe_mutable_byte_array_peerless_recvfrom fd b off len flags-    >>= errorsFromSize---- | Receive data into an address from a network socket. This uses the unsafe---   FFI. This does not return the socket address of the remote host that---   sent the packet received.-uninterruptibleReceiveFrom_ ::-     Fd -- ^ Socket-  -> Addr -- ^ Destination byte array-  -> CSize -- ^ Maximum bytes to receive-  -> MessageFlags 'Receive -- ^ Flags-  -> IO (Either Errno CSize) -- ^ Number of bytes received into array-{-# inline uninterruptibleReceiveFrom_ #-}-uninterruptibleReceiveFrom_ !fd (Addr !b) !len !flags =-  c_unsafe_addr_peerless_recvfrom fd b len flags-    >>= errorsFromSize--ptrToAddr :: Ptr Word8 -> Addr-ptrToAddr (Exts.Ptr a) = Addr a---- | Shutdown a socket. This uses the unsafe FFI.-uninterruptibleShutdown ::-     Fd-  -> ShutdownType-  -> IO (Either Errno ())-uninterruptibleShutdown fd typ =-  c_unsafe_shutdown fd typ >>= errorsFromInt_--errorsFromSize :: CSsize -> IO (Either Errno CSize)-errorsFromSize r = if r > (-1)-  then pure (Right (cssizeToCSize r))-  else fmap Left getErrno--errorsFromFd :: Fd -> IO (Either Errno Fd)-errorsFromFd r = if r > (-1)-  then pure (Right r)-  else fmap Left getErrno---- Sometimes, functions that return an int use zero to indicate--- success and negative one to indicate failure without including--- additional information in the value.-errorsFromInt_ :: CInt -> IO (Either Errno ())-errorsFromInt_ r = if r == 0-  then pure (Right ())-  else fmap Left getErrno--intToCInt :: Int -> CInt-intToCInt = fromIntegral--intToCSize :: Int -> CSize-intToCSize = fromIntegral--cintToInt :: CInt -> Int-cintToInt = fromIntegral--csizeToInt :: CSize -> Int-csizeToInt = fromIntegral--cssizeToInt :: CSsize -> Int-cssizeToInt = fromIntegral---- only call this when it is known that the argument is non-negative-cssizeToCSize :: CSsize -> CSize-cssizeToCSize = fromIntegral--shrinkMutableByteArray :: MutableByteArray RealWorld -> Int -> IO ()-shrinkMutableByteArray (MutableByteArray arr) (I# sz) =-  PM.primitive_ (shrinkMutableByteArray# arr sz)---- | Convert a 16-bit word from host to network byte order (e.g. @htons@).-hostToNetworkShort :: Word16 -> Word16-hostToNetworkShort = case targetByteOrder of-  BigEndian -> id-  LittleEndian -> byteSwap16---- | Convert a 16-bit word from network to host byte order (e.g. @ntohs@).-networkToHostShort :: Word16 -> Word16-networkToHostShort = case targetByteOrder of-  BigEndian -> id-  LittleEndian -> byteSwap16---- | Convert a 32-bit word from host to network byte order (e.g. @htonl@).-hostToNetworkLong :: Word32 -> Word32-hostToNetworkLong = case targetByteOrder of-  BigEndian -> id-  LittleEndian -> byteSwap32---- | Convert a 32-bit word from network to host byte order (e.g. @ntohl@).-networkToHostLong :: Word32 -> Word32-networkToHostLong = case targetByteOrder of-  BigEndian -> id-  LittleEndian -> byteSwap32--pokeMessageHeader :: Addr -> Addr -> CInt -> Addr -> CSize -> Addr -> CSize -> MessageFlags 'Receive -> IO ()-pokeMessageHeader msgHdrAddr a b c d e f g = do-  PST.pokeMessageHeaderName msgHdrAddr a-  PST.pokeMessageHeaderNameLength msgHdrAddr b-  PST.pokeMessageHeaderIOVector msgHdrAddr c-  PST.pokeMessageHeaderIOVectorLength msgHdrAddr d-  PST.pokeMessageHeaderControl msgHdrAddr e-  PST.pokeMessageHeaderControlLength msgHdrAddr f-  PST.pokeMessageHeaderFlags msgHdrAddr g--#if defined(UNLIFTEDARRAYFUNCTIONS)--- | Write data from multiple byte arrays to the file/socket associated---   with the file descriptor. This does not support slicing. The---   <http://pubs.opengroup.org/onlinepubs/009604499/functions/writev.html POSIX specification>---   of @writev@ includes more details.-writeVector ::-     Fd -- ^ Socket-  -> UnliftedArray ByteArray -- ^ Source byte arrays-  -> IO (Either Errno CSize)-writeVector fd buffers = do-  iovecs@(MutableByteArray iovecs#) :: MutableByteArray RealWorld <--    PM.newPinnedByteArray-      (cintToInt PST.sizeofIOVector * PM.sizeofUnliftedArray buffers)-  -- We construct a list of the new buffers for the sole purpose-  -- of ensuring that we can touch the list later to keep all-  -- the new buffers live.-  newBufs <- foldDownward (PM.sizeofUnliftedArray buffers) UNil $ \newBufs i -> do-    let !buf = PM.indexUnliftedArray buffers i-    pinByteArray buf >>= \case-      Nothing -> do-        let buffer = buf-        let targetAddr :: Addr-            targetAddr = ptrToAddr (PM.mutableByteArrayContents iovecs) `plusAddr`-              (i * cintToInt PST.sizeofIOVector)-        PST.pokeIOVectorBase targetAddr (ptrToAddr (PM.byteArrayContents buffer))-        PST.pokeIOVectorLength targetAddr (intToCSize (PM.sizeofByteArray buffer))-        pure newBufs-      Just buffer -> do-        let targetAddr :: Addr-            targetAddr = ptrToAddr (PM.mutableByteArrayContents iovecs) `plusAddr`-              (i * cintToInt PST.sizeofIOVector)-        PST.pokeIOVectorBase targetAddr (ptrToAddr (PM.byteArrayContents buffer))-        PST.pokeIOVectorLength targetAddr (intToCSize (PM.sizeofByteArray buffer))-        pure (UCons (unByteArray buffer) newBufs)-  r <- errorsFromSize =<<-    c_safe_writev fd iovecs# (intToCInt (PM.sizeofUnliftedArray buffers))-  -- Touching both the unlifted array and the list of new buffers-  -- here is crucial to ensuring that-  -- the buffers do not get GCed before c_safe_writev. Just touching-  -- them should keep all of their children alive too.-  touchUnliftedArray buffers-  touchLifted newBufs-  pure r---- | Send many immutable byte arrays with @sendmsg@.--- This accepts a slice into the chunks. Additionally,--- this accepts an offset into the first chunk.-uninterruptibleSendByteArrays ::-     Fd -- ^ Socket-  -> UnliftedArray ByteArray -- ^ Byte arrays-  -> Int -- ^ Offset into byte array chunks-  -> Int -- ^ Number of chunks to send-  -> Int -- ^ Offset into first chunk-  -> MessageFlags 'Send-  -> IO (Either Errno CSize)-{-# inline uninterruptibleSendByteArrays #-}-uninterruptibleSendByteArrays !fd (UnliftedArray arrs)-  off !len !offC !flags =-    c_unsafe_sendmsg_bytearrays fd arrs off len offC flags-      >>= errorsFromSize---- | Receive a message, scattering the input. This does not provide---   the socket address or the control messages. All of the chunks---   must have the same maximum size. All resulting byte arrays have---   been explicitly pinned.-uninterruptibleReceiveMessageA ::-     Fd -- ^ Socket-  -> CSize -- ^ Maximum bytes per chunk-  -> CSize -- ^ Maximum number of chunks-  -> MessageFlags 'Receive -- ^ Flags-  -> IO (Either Errno (CSize,UnliftedArray ByteArray))-uninterruptibleReceiveMessageA !s !chunkSize !chunkCount !flags = do-  bufs <- PM.unsafeNewUnliftedArray (csizeToInt chunkCount)-  iovecsBuf <- PM.newPinnedByteArray (csizeToInt chunkCount * cintToInt PST.sizeofIOVector)-  let iovecsAddr = ptrToAddr (PM.mutableByteArrayContents iovecsBuf)-  initializeIOVectors bufs iovecsAddr chunkSize chunkCount-  msgHdrBuf <- PM.newPinnedByteArray (cintToInt PST.sizeofMessageHeader)-  let !msgHdrAddr@(Addr msgHdrAddr#) = ptrToAddr (PM.mutableByteArrayContents msgHdrBuf)-  pokeMessageHeader msgHdrAddr nullAddr 0 iovecsAddr chunkCount nullAddr 0 flags-  r <- c_unsafe_addr_recvmsg s msgHdrAddr# flags-  if r > (-1)-    then do-      filled <- countAndShrinkIOVectors (csizeToInt chunkCount) (cssizeToInt r) (csizeToInt chunkSize) bufs-      frozenBufs <- deepFreezeIOVectors filled bufs-      touchMutableUnliftedArray bufs-      touchMutableByteArray iovecsBuf-      touchMutableByteArray msgHdrBuf-      pure (Right (cssizeToCSize r,frozenBufs))-    else do-      touchMutableUnliftedArray bufs-      touchMutableByteArray iovecsBuf-      touchMutableByteArray msgHdrBuf-      fmap Left getErrno---- | Receive a message, scattering the input. This provides the socket---   address but does not include control messages. All of the chunks---   must have the same maximum size. All resulting byte arrays have---   been explicitly pinned.-uninterruptibleReceiveMessageB ::-     Fd -- ^ Socket-  -> CSize -- ^ Maximum bytes per chunk-  -> CSize -- ^ Maximum number of chunks-  -> MessageFlags 'Receive -- ^ Flags-  -> CInt -- ^ Maximum socket address size-  -> IO (Either Errno (CInt,SocketAddress,CSize,UnliftedArray ByteArray))-uninterruptibleReceiveMessageB !s !chunkSize !chunkCount !flags !maxSockAddrSz = do-  sockAddrBuf <- PM.newPinnedByteArray (cintToInt maxSockAddrSz)-  bufs <- PM.unsafeNewUnliftedArray (csizeToInt chunkCount)-  iovecsBuf <- PM.newPinnedByteArray (csizeToInt chunkCount * cintToInt PST.sizeofIOVector)-  let iovecsAddr = ptrToAddr (PM.mutableByteArrayContents iovecsBuf)-  initializeIOVectors bufs iovecsAddr chunkSize chunkCount-  msgHdrBuf <- PM.newPinnedByteArray (cintToInt PST.sizeofMessageHeader)-  let !msgHdrAddr@(Addr msgHdrAddr#) = ptrToAddr (PM.mutableByteArrayContents msgHdrBuf)-  pokeMessageHeader msgHdrAddr-    (ptrToAddr (PM.mutableByteArrayContents sockAddrBuf)) maxSockAddrSz iovecsAddr-    chunkCount nullAddr 0 flags-  r <- c_unsafe_addr_recvmsg s msgHdrAddr# flags-  if r > (-1)-    then do-      actualSockAddrSz <- PST.peekMessageHeaderNameLength msgHdrAddr-      if actualSockAddrSz < maxSockAddrSz-        then shrinkMutableByteArray sockAddrBuf (cintToInt actualSockAddrSz)-        else pure ()-      sockAddr <- PM.unsafeFreezeByteArray sockAddrBuf-      filled <- countAndShrinkIOVectors (csizeToInt chunkCount) (cssizeToInt r) (csizeToInt chunkSize) bufs-      frozenBufs <- deepFreezeIOVectors filled bufs-      touchMutableUnliftedArray bufs-      touchMutableByteArray iovecsBuf-      touchMutableByteArray msgHdrBuf-      touchMutableByteArray sockAddrBuf-      pure (Right (actualSockAddrSz,SocketAddress sockAddr,cssizeToCSize r,frozenBufs))-    else do-      touchMutableUnliftedArray bufs-      touchMutableByteArray iovecsBuf-      touchMutableByteArray msgHdrBuf-      touchMutableByteArray sockAddrBuf-      fmap Left getErrno---- This sets up an array of iovec. The iov_len is assigned to the--- same length in all of these. The actual buffers are allocated--- and stuck in an unlifted array. Pointers to these buffers (we can--- do that because they are pinned) go in the iov_base field.-initializeIOVectors ::-     MutableUnliftedArray RealWorld (MutableByteArray RealWorld) -- buffers-  -> Addr -- array of iovec-  -> CSize -- chunk size-  -> CSize -- chunk count-  -> IO ()-initializeIOVectors bufs iovecsAddr chunkSize chunkCount =-  let go !ix !iovecAddr = if ix < csizeToInt chunkCount-        then do-          initializeIOVector bufs iovecAddr chunkSize ix-          go (ix + 1) (plusAddr iovecAddr (cintToInt PST.sizeofIOVector))-        else pure ()-   in go 0 iovecsAddr---- Initialize a single iovec. We write the pinned byte array into--- both the iov_base field and into an unlifted array. There is a--- copy of this function in Linux.Socket.-initializeIOVector ::-     MutableUnliftedArray RealWorld (MutableByteArray RealWorld)-  -> Addr-  -> CSize-  -> Int-  -> IO ()-initializeIOVector bufs iovecAddr chunkSize ix = do-  buf <- PM.newPinnedByteArray (csizeToInt chunkSize)-  PM.writeUnliftedArray bufs ix buf-  let !(Exts.Ptr bufAddr#) = PM.mutableByteArrayContents buf-      bufAddr = Addr bufAddr#-  PST.pokeIOVectorBase iovecAddr bufAddr-  PST.pokeIOVectorLength iovecAddr chunkSize---- This is intended to be called on an array of iovec after recvmsg--- and before deepFreezeIOVectors. An adaptation of this function exists--- in Linux.Socket.-countAndShrinkIOVectors ::-     Int -- Total number of supplied iovecs-  -> Int -- Total amount of space used by receive-  -> Int -- Amount of space per buffer (each buffer must have equal size)-  -> MutableUnliftedArray RealWorld (MutableByteArray RealWorld)-  -> IO Int-countAndShrinkIOVectors !n !totalUsedSz !maxBufSz !bufs = go 0 totalUsedSz where-  -- This outer if (checking that the index is in bounds) should-  -- not actually be necessary. I will remove once the test suite-  -- bolsters my confidence.-  go !ix !remainingBytes = if ix < n-    then if remainingBytes >= maxBufSz-      then go-        (ix + 1)-        (remainingBytes - maxBufSz)-      else if remainingBytes == 0-        then pure ix-        else do-          buf <- PM.readUnliftedArray bufs ix-          shrinkMutableByteArray buf remainingBytes-          pure (ix + 1)-    else pure ix---- Freeze a slice of the mutable byte arrays inside the unlifted--- array. This copies makes a copy of the slice of the original--- array. A copy of this function exists in Linux.Socket.-deepFreezeIOVectors ::-     Int -- How many iovecs actually had a non-zero number of bytes-  -> MutableUnliftedArray RealWorld (MutableByteArray RealWorld)-  -> IO (UnliftedArray ByteArray)-deepFreezeIOVectors n m = do-  x <- PM.unsafeNewUnliftedArray n-  let go !ix = if ix < n-        then do-          PM.writeUnliftedArray x ix =<< PM.unsafeFreezeByteArray =<< PM.readUnliftedArray m ix-          go (ix + 1)-        else PM.unsafeFreezeUnliftedArray x-  go 0--touchMutableUnliftedArray :: MutableUnliftedArray RealWorld a -> IO ()-touchMutableUnliftedArray (MutableUnliftedArray x) = touchMutableUnliftedArray# x--touchUnliftedArray :: UnliftedArray a -> IO ()-touchUnliftedArray (UnliftedArray x) = touchUnliftedArray# x--touchMutableUnliftedArray# :: MutableUnliftedArray# RealWorld a -> IO ()-touchMutableUnliftedArray# x = IO $ \s -> case touch# x s of s' -> (# s', () #)--touchUnliftedArray# :: UnliftedArray# a -> IO ()-touchUnliftedArray# x = IO $ \s -> case touch# x s of s' -> (# s', () #)-#endif--unByteArray :: ByteArray -> ByteArray#-unByteArray (ByteArray x) = x--touchMutableByteArray :: MutableByteArray RealWorld -> IO ()-touchMutableByteArray (MutableByteArray x) = touchMutableByteArray# x--touchMutableByteArray# :: MutableByteArray# RealWorld -> IO ()-touchMutableByteArray# x = IO $ \s -> case touch# x s of s' -> (# s', () #)--touchLifted :: a -> IO ()-touchLifted x = IO $ \s -> case touch# x s of s' -> (# s', () #)--{- $conversion-These functions are used to convert IPv4 addresses and ports between network-byte order and host byte order. They are essential when working with-'SocketAddressInternet'. To avoid getting in the way of GHC compile-time-optimizations, these functions are not actually implemented with FFI-calls to @htonl@ and friends. Rather, they are reimplemented in haskell.--}---{- $receiveMessage-The function @recvMsg@ presents us with a challenge. Since it uses a-data structure with many nested pointers, we have to use pinned byte-arrays for everything. There is also the difficulty of marshalling-haskell's unlifted array (array of arrays) type into what C's-array of @iovec@. There's the question of the array of @cmsghdr@s.-On top of all of this, we have to answer the question of whether-we want to accept mutable buffer or whether we want to do the-allocations internally (both for the buffers and for the ancilliary-data structurs needed to massage the data into what C expects).--What we do to handle this in offer several variants of @recvmsg@-ending in @A@, @B@, etc.--}--isByteArrayPinned :: ByteArray -> Bool-{-# inline isByteArrayPinned #-}-isByteArrayPinned (ByteArray arr#) =-  Exts.isTrue# (Exts.isByteArrayPinned# arr#)--isMutableByteArrayPinned :: MutableByteArray s -> Bool-{-# inline isMutableByteArrayPinned #-}-isMutableByteArrayPinned (MutableByteArray marr#) =-  Exts.isTrue# (Exts.isMutableByteArrayPinned# marr#)--unMba :: MutableByteArray s -> MutableByteArray# s-{-# inline unMba #-}+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE CPP #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE DuplicateRecordFields #-}+{-# LANGUAGE GADTSyntax #-}+{-# LANGUAGE KindSignatures #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE MagicHash #-}+{-# LANGUAGE NamedFieldPuns #-}+{-# LANGUAGE PatternSynonyms #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE UnliftedFFITypes #-}++{- | Types and functions related to the POSIX sockets API.+  Unusual characteristics:++  * Any time the standard calls for @socklen_t@, we use+    @CInt@ instead. Linus Torvalds <https://yarchive.net/comp/linux/socklen_t.html writes>+    that \"Any sane library must have @socklen_t@ be the same size as @int@.+    Anything else breaks any BSD socket layer stuff.\"+  * Send and receive each have several variants. They are distinguished by+    the safe\/unsafe FFI use and by the @Addr@\/@ByteArray@/@MutableByteArray@+    buffer type. They all call @send@ or @recv@ exactly once. They do not+    repeatedly make syscalls like some of the functions in @network@.+    Users who want that behavior need to build on top of this package.+  * There are no requirements on the pinnedness of @ByteArray@ arguments+    passed to any of these functions. If wrappers of the safe FFI are+    passed unpinned @ByteArray@ arguments, they will copy the contents+    into pinned memory before invoking the foreign function.+-}+module Posix.Socket+  ( -- * Functions++    -- ** Socket+    uninterruptibleSocket+  , socket+  , withSocket++    -- ** Socket Pair+  , uninterruptibleSocketPair++    -- ** Address Resolution+  , getAddressInfo+  , uninterruptibleFreeAddressInfo++    -- ** Bind+  , uninterruptibleBind++    -- ** Connect+  , connect+  , uninterruptibleConnect+  , uninterruptibleConnectPtr++    -- ** Listen+  , uninterruptibleListen++    -- ** Accept+  , accept+  , uninterruptibleAccept+  , accept_++    -- ** Get Socket Name+  , uninterruptibleGetSocketName++    -- ** Get Socket Option+  , uninterruptibleGetSocketOption++    -- ** Set Socket Option+  , uninterruptibleSetSocketOption+  , uninterruptibleSetSocketOptionByteArray+  , uninterruptibleSetSocketOptionInt++    -- ** Close+  , F.close+  , F.uninterruptibleClose+  , F.uninterruptibleErrorlessClose++    -- ** Shutdown+  , uninterruptibleShutdown++    -- ** Send+  , send+  , sendByteArray+  , sendMutableByteArray+  , uninterruptibleSend+  , uninterruptibleSendByteArray+  , uninterruptibleSendMutableByteArray++    -- ** Send To+  , uninterruptibleSendToByteArray+  , uninterruptibleSendToMutableByteArray+  , uninterruptibleSendToInternet+  , uninterruptibleSendToInternetByteArray+  , uninterruptibleSendToInternetMutableByteArray++    -- ** Write Vector++    -- ** Receive+  , receive+  , receiveByteArray+  , uninterruptibleReceive+  , uninterruptibleReceiveMutableByteArray++    -- ** Receive From+  , uninterruptibleReceiveFromMutableByteArray+  , uninterruptibleReceiveFromMutableByteArray_+  , uninterruptibleReceiveFrom_+  , uninterruptibleReceiveFromInternet+  , uninterruptibleReceiveFromInternetMutableByteArray++    -- ** Receive Message+    -- $receiveMessage+  , uninterruptibleSendMessageA+  , uninterruptibleSendMessageB++    -- ** Byte-Order Conversion+    -- $conversion+  , hostToNetworkLong+  , hostToNetworkShort+  , networkToHostLong+  , networkToHostShort++    -- * Types+  , Family (..)+  , Type (..)+  , Protocol (..)+  , OptionName (..)+  , OptionValue (..)+  , Level (..)+  , Message (..)+  , MessageFlags (..)+  , ShutdownType (..)+  , AddressInfo++    -- * Socket Address++    -- ** Types+  , SocketAddress (..)+  , PST.SocketAddressInternet (..)+  , PST.SocketAddressUnix (..)++    -- ** Encoding+  , PSP.encodeSocketAddressInternet+  , PSP.encodeSocketAddressUnix++    -- ** Decoding+  , PSP.decodeSocketAddressInternet+  , PSP.indexSocketAddressInternet++    -- ** Sizes+  , PSP.sizeofSocketAddressInternet++    -- * Data Construction++    -- ** Socket Domains+  , pattern PST.Unix+  , pattern PST.Unspecified+  , pattern PST.Internet+  , pattern PST.Internet6++    -- ** Socket Types+  , PST.stream+  , PST.datagram+  , PST.raw+  , PST.sequencedPacket++    -- ** Protocols+  , PST.defaultProtocol+  , PST.rawProtocol+  , PST.icmp+  , PST.tcp+  , PST.udp+  , PST.ip+  , PST.ipv6++    -- ** Receive Flags+  , PST.peek+  , PST.outOfBand+  , PST.waitAll++    -- ** Send Flags+  , PST.noSignal++    -- ** Shutdown Types+  , PST.read+  , PST.write+  , PST.readWrite++    -- ** Socket Levels+  , PST.levelSocket++    -- ** Option Names+  , PST.optionError+  , PST.bindToDevice+  , PST.broadcast+  , PST.reuseAddress++    -- ** Address Info++    -- *** Peek+  , PST.peekAddressInfoFlags++    -- *** Poke+  , PST.pokeAddressInfoFlags++    -- *** Metadata+  , PST.sizeofAddressInfo++    -- ** Message Header++    -- *** Peek+  , PST.peekMessageHeaderName+  , PST.peekMessageHeaderNameLength+  , PST.peekMessageHeaderIOVector+  , PST.peekMessageHeaderIOVectorLength+  , PST.peekMessageHeaderControl+  , PST.peekMessageHeaderControlLength+  , PST.peekMessageHeaderFlags+  , PST.peekControlMessageHeaderLevel+  , PST.peekControlMessageHeaderLength+  , PST.peekControlMessageHeaderType++    -- *** Poke+  , PST.pokeMessageHeaderName+  , PST.pokeMessageHeaderNameLength+  , PST.pokeMessageHeaderIOVector+  , PST.pokeMessageHeaderIOVectorLength+  , PST.pokeMessageHeaderControl+  , PST.pokeMessageHeaderControlLength+  , PST.pokeMessageHeaderFlags++    -- *** Metadata+  , PST.sizeofMessageHeader++    -- ** IO Vector++    -- *** Peek+  , PST.peekIOVectorBase+  , PST.peekIOVectorLength++    -- *** Poke+  , PST.pokeIOVectorBase+  , PST.pokeIOVectorLength++    -- *** Metadata+  , PST.sizeofIOVector+  ) where++import Control.Exception (mask, onException)+import Data.Primitive (ByteArray (..), MutableByteArray (..), MutablePrimArray (..))+import Data.Primitive.Addr (Addr (..))+import Data.Primitive.ByteArray.Offset (MutableByteArrayOffset (..))+import Data.Primitive.PrimArray.Offset (MutablePrimArrayOffset (..))+import Data.Void (Void)+import Data.Word (Word16, Word32, Word8, byteSwap16, byteSwap32)+import Foreign.C.Error (Errno (Errno), getErrno)+import Foreign.C.String (CString)+import Foreign.C.Types (CInt (..), CSize (..))+import Foreign.Ptr (nullPtr)+import GHC.ByteOrder (ByteOrder (BigEndian, LittleEndian), targetByteOrder)+import GHC.Exts (Addr#, ByteArray#, Int (I#), MutableByteArray#, Ptr (Ptr), RealWorld, shrinkMutableByteArray#)+import Posix.Socket.Types+  ( AddressInfo+  , Family (..)+  , Level (..)+  , Message (..)+  , MessageFlags (..)+  , OptionName (..)+  , OptionValue (..)+  , Protocol (..)+  , ShutdownType (..)+  , SocketAddress (..)+  , SocketAddressInternet (..)+  , Type (..)+  )+import System.Posix.Types (CSsize (..), Fd (..))++import qualified Control.Monad.Primitive as PM+import qualified Data.Primitive as PM+import qualified GHC.Exts as Exts+import qualified Posix.File as F+import qualified Posix.Socket.Types as PST++-- This module include operating-system specific code used+-- to serialize some of various kind of socket address types.+import qualified Posix.Socket.Platform as PSP++-- getaddrinfo cannot use the unsafe ffi+foreign import ccall safe "sys/socket.h getaddrinfo"+  c_safe_getaddrinfo ::+    CString ->+    CString ->+    Ptr AddressInfo ->+    MutableByteArray# RealWorld -> -- actually a `Ptr (Ptr AddressInfo))`.+    IO Errno++-- | Free the @addrinfo@ at the pointer.+foreign import ccall safe "sys/socket.h freeaddrinfo"+  uninterruptibleFreeAddressInfo :: Ptr AddressInfo -> IO ()++foreign import ccall unsafe "sys/socket.h socket"+  c_socket :: Family -> Type -> Protocol -> IO Fd++foreign import ccall unsafe "sys/socket.h socketpair"+  c_socketpair :: Family -> Type -> Protocol -> MutableByteArray# RealWorld -> IO CInt++foreign import ccall unsafe "sys/socket.h listen"+  c_listen :: Fd -> CInt -> IO CInt++foreign import ccall unsafe "unistd.h shutdown"+  c_unsafe_shutdown :: Fd -> ShutdownType -> IO CInt++-- Per the spec, the type signature of bind is:+--   int bind(int socket, const struct sockaddr *address, socklen_t address_len);+-- However, here we choose to represent the third argument as+-- CInt rather than introducing a type corresponding to socklen_t.+-- According to Linus Torvalds, "Any sane library must have socklen_t+-- be the same size as int. Anything else breaks any BSD socket layer stuff."+-- (https://yarchive.net/comp/linux/socklen_t.html). If a platform+-- violates this assumption, this wrapper will be broken on that platform.+foreign import ccall unsafe "sys/socket.h bind"+  c_bind :: Fd -> ByteArray# -> CInt -> IO CInt++-- Per the spec, the type signature of accept is:+--   int accept(int socket, struct sockaddr *restrict address, socklen_t *restrict address_len);+-- The restrict keyword does not matter much for our purposes. See the+-- note on c_bind for why we use CInt for socklen_t. Remember that the+-- first bytearray argument is actually SocketAddress in the function that+-- wraps this one. The second bytearray argument is a pointer to the size.+foreign import ccall safe "sys/socket.h accept"+  c_safe_accept ::+    Fd ->+    MutableByteArray# RealWorld -> -- SocketAddress+    MutableByteArray# RealWorld -> -- Ptr CInt+    IO Fd+foreign import ccall unsafe "sys/socket.h accept"+  c_unsafe_accept ::+    Fd ->+    MutableByteArray# RealWorld -> -- SocketAddress+    MutableByteArray# RealWorld -> -- Ptr CInt+    IO Fd++-- This variant of accept is used when we do not care about the+-- remote sockaddr. We pass null.+foreign import ccall safe "sys/socket.h accept"+  c_safe_ptr_accept :: Fd -> Ptr Void -> Ptr CInt -> IO Fd++foreign import ccall unsafe "sys/socket.h getsockname"+  c_unsafe_getsockname ::+    Fd ->+    MutableByteArray# RealWorld -> -- SocketAddress+    MutableByteArray# RealWorld -> -- Addr length (Ptr CInt)+    IO CInt++foreign import ccall unsafe "sys/socket.h getsockopt"+  c_unsafe_getsockopt ::+    Fd ->+    Level ->+    OptionName ->+    MutableByteArray# RealWorld -> -- Option value+    MutableByteArray# RealWorld -> -- Option len (Ptr CInt)+    IO CInt++foreign import ccall unsafe "sys/socket.h setsockopt_int"+  c_unsafe_setsockopt_int ::+    Fd ->+    Level ->+    OptionName ->+    CInt -> -- option_value+    IO CInt++foreign import ccall unsafe "sys/socket.h setsockopt"+  c_unsafe_setsockopt ::+    Fd ->+    Level ->+    OptionName ->+    Ptr Void -> -- option_val+    CInt -> -- option_len+    IO CInt++foreign import ccall unsafe "sys/socket.h setsockopt"+  c_unsafe_setsockopt_ba ::+    Fd ->+    Level ->+    OptionName ->+    ByteArray# -> -- option_val+    CInt -> -- option_len+    IO CInt++-- Per the spec the type signature of connect is:+--   int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);+-- The bytearray argument is actually SocketAddress.+foreign import ccall safe "sys/socket.h connect"+  c_safe_connect :: Fd -> ByteArray# -> CInt -> IO CInt+foreign import ccall safe "sys/socket.h connect"+  c_safe_mutablebytearray_connect :: Fd -> MutableByteArray# RealWorld -> CInt -> IO CInt+foreign import ccall unsafe "sys/socket.h connect"+  c_unsafe_connect :: Fd -> ByteArray# -> CInt -> IO CInt+foreign import ccall unsafe "sys/socket.h connect"+  c_unsafe_connect_addr :: Fd -> Addr# -> CInt -> IO CInt++-- There are several options for wrapping send. Both safe and unsafe+-- are useful. Additionally, in the unsafe category, we also+-- have the option of writing to either an address or a byte array.+-- Unsafe FFI calls guarantee that byte arrays will not be relocated+-- while the FFI call is taking place. Safe FFI calls do not have+-- this guarantee, so internally we must be careful when using these to only+-- provide pinned byte arrays as arguments.+foreign import ccall safe "sys/socket.h send"+  c_safe_addr_send :: Fd -> Addr# -> CSize -> MessageFlags 'Send -> IO CSsize+foreign import ccall safe "sys/socket.h send_offset"+  c_safe_bytearray_send :: Fd -> ByteArray# -> Int -> CSize -> MessageFlags 'Send -> IO CSsize+foreign import ccall safe "sys/socket.h send_offset"+  c_safe_mutablebytearray_send :: Fd -> MutableByteArray# RealWorld -> Int -> CSize -> MessageFlags 'Send -> IO CSsize+foreign import ccall safe "sys/socket.h send"+  c_safe_mutablebytearray_no_offset_send :: Fd -> MutableByteArray# RealWorld -> CSize -> MessageFlags 'Send -> IO CSsize+foreign import ccall unsafe "sys/socket.h send"+  c_unsafe_addr_send :: Fd -> Addr# -> CSize -> MessageFlags 'Send -> IO CSsize+foreign import ccall unsafe "sys/socket.h send_offset"+  c_unsafe_bytearray_send :: Fd -> ByteArray# -> Int -> CSize -> MessageFlags 'Send -> IO CSsize+foreign import ccall unsafe "sys/socket.h send_offset"+  c_unsafe_mutable_bytearray_send :: Fd -> MutableByteArray# RealWorld -> Int -> CSize -> MessageFlags 'Send -> IO CSsize++-- The ByteArray# (second to last argument) is a SocketAddress.+foreign import ccall unsafe "sys/socket.h sendto_offset"+  c_unsafe_bytearray_sendto :: Fd -> ByteArray# -> Int -> CSize -> MessageFlags 'Send -> ByteArray# -> CInt -> IO CSsize++-- The ByteArray# (second to last argument) is a SocketAddress.+foreign import ccall unsafe "sys/socket.h sendto_offset"+  c_unsafe_mutable_bytearray_sendto :: Fd -> MutableByteArray# RealWorld -> Int -> CSize -> MessageFlags 'Send -> ByteArray# -> CInt -> IO CSsize+foreign import ccall unsafe "sys/socket.h sendto_inet_offset"+  c_unsafe_mutable_bytearray_sendto_inet :: Fd -> MutableByteArray# RealWorld -> Int -> CSize -> MessageFlags 'Send -> Word16 -> Word32 -> IO CSsize+foreign import ccall unsafe "HaskellPosix.h sendto_inet_offset"+  c_unsafe_bytearray_sendto_inet :: Fd -> ByteArray# -> Int -> CSize -> MessageFlags 'Send -> Word16 -> Word32 -> IO CSsize+foreign import ccall unsafe "HaskellPosix.h sendto_inet_addr"+  c_unsafe_addr_sendto_inet :: Fd -> Addr# -> CSize -> MessageFlags 'Send -> Word16 -> Word32 -> IO CSsize++foreign import ccall unsafe "HaskellPosix.h sendmsg_a"+  c_unsafe_sendmsg_a :: Fd -> Addr# -> CSize -> MutableByteArray# RealWorld -> Int -> CSize -> MessageFlags 'Send -> IO CSsize++foreign import ccall unsafe "HaskellPosix.h sendmsg_b"+  c_unsafe_sendmsg_b :: Fd -> MutableByteArray# RealWorld -> Int -> CSize -> Addr# -> CSize -> MessageFlags 'Send -> IO CSsize++-- There are several ways to wrap recv.+foreign import ccall safe "sys/socket.h recv"+  c_safe_addr_recv :: Fd -> Addr# -> CSize -> MessageFlags 'Receive -> IO CSsize+foreign import ccall unsafe "sys/socket.h recv"+  c_unsafe_addr_recv :: Fd -> Addr# -> CSize -> MessageFlags 'Receive -> IO CSsize+foreign import ccall unsafe "sys/socket.h recv_offset"+  c_unsafe_mutable_byte_array_recv :: Fd -> MutableByteArray# RealWorld -> Int -> CSize -> MessageFlags 'Receive -> IO CSsize++-- The last two arguments are SocketAddress and Ptr CInt.+foreign import ccall unsafe "sys/socket.h recvfrom_offset"+  c_unsafe_mutable_byte_array_recvfrom :: Fd -> MutableByteArray# RealWorld -> Int -> CSize -> MessageFlags 'Receive -> MutableByteArray# RealWorld -> MutableByteArray# RealWorld -> IO CSsize+foreign import ccall unsafe "sys/socket.h recvfrom_offset_peerless"+  c_unsafe_mutable_byte_array_peerless_recvfrom ::+    Fd ->+    MutableByteArray# RealWorld ->+    Int ->+    CSize ->+    MessageFlags 'Receive ->+    IO CSsize+foreign import ccall unsafe "sys/socket.h recvfrom_addr_peerless"+  c_unsafe_addr_peerless_recvfrom ::+    Fd -> Addr# -> CSize -> MessageFlags 'Receive -> IO CSsize+foreign import ccall unsafe "sys/socket.h recvfrom_offset_inet"+  c_unsafe_recvfrom_inet ::+    Fd ->+    MutableByteArray# RealWorld ->+    Int ->+    CSize ->+    MessageFlags 'Receive ->+    MutableByteArray# RealWorld ->+    Int ->+    IO CSsize+foreign import ccall unsafe "sys/socket.h recvfrom_offset_inet_addr"+  c_unsafe_recvfrom_inet_addr ::+    Fd ->+    Addr# ->+    CSize ->+    MessageFlags 'Receive ->+    MutableByteArray# RealWorld ->+    Int ->+    IO CSsize++{- | Create an endpoint for communication, returning a file+  descriptor that refers to that endpoint. The+  <http://pubs.opengroup.org/onlinepubs/9699919799/functions/socket.html POSIX specification>+  includes more details. No special preparation is required before calling+  this function. The author believes that it cannot block for a prolonged+  period of time.+-}+uninterruptibleSocket ::+  -- | Communications domain (e.g. 'internet', 'unix')+  Family ->+  -- | Socket type (e.g. 'datagram', 'stream') with flags+  Type ->+  -- | Protocol+  Protocol ->+  IO (Either Errno Fd)+uninterruptibleSocket dom typ prot = c_socket dom typ prot >>= errorsFromFd++-- | Alias for 'uninterruptibleSocket'.+socket ::+  -- | Communications domain (e.g. 'internet', 'unix')+  Family ->+  -- | Socket type (e.g. 'datagram', 'stream') with flags+  Type ->+  -- | Protocol+  Protocol ->+  IO (Either Errno Fd)+socket = uninterruptibleSocket++{- | Helper function for the common case where 'socket' or+'uninterruptibleSocket' is paired with 'close'. This ensures that the+socket is closed even in the case of an exception. Do not call 'close' in+the callback since 'close' is called by this function after the callback+completes (or after an exception is thrown).++This is implementated with @mask@ (and restore) and @onException@+directly rather than with @bracket@.+-}+withSocket ::+  -- | Communications domain (e.g. 'internet', 'unix')+  Family ->+  -- | Socket type (e.g. 'datagram', 'stream') with flags+  Type ->+  -- | Protocol+  Protocol ->+  -- | Callback that uses the socket. Must not close the socket.+  -- The callback is not used when the @socket()@ call fails.+  (Fd -> IO a) ->+  IO (Either Errno a)+{-# INLINE withSocket #-}+withSocket !dom !typ !prot cb =+  mask $ \restore -> do+    r <- c_socket dom typ prot+    if r > (-1)+      then do+        a <- restore (cb r) `onException` F.close r+        _ <- F.close r+        pure (Right a)+      else fmap Left getErrno++{- | Create an unbound pair of connected sockets in a specified domain, of+  a specified type, under the protocol optionally specified by the protocol+  argument. The <http://pubs.opengroup.org/onlinepubs/9699919799/functions/socketpair.html POSIX specification>+  includes more details. No special preparation is required before calling+  this function. The author believes that it cannot block for a prolonged+  period of time.+-}+uninterruptibleSocketPair ::+  -- | Communications domain (probably 'unix')+  Family ->+  -- | Socket type (e.g. 'datagram', 'stream') with flags+  Type ->+  -- | Protocol+  Protocol ->+  IO (Either Errno (Fd, Fd))+uninterruptibleSocketPair dom typ prot = do+  -- If this ever switches to the safe FFI, we will need to use+  -- a pinned array here instead.+  (sockets@(MutablePrimArray sockets#) :: MutablePrimArray RealWorld Fd) <- PM.newPrimArray 2+  r <- c_socketpair dom typ prot sockets#+  if r == 0+    then do+      fd1 <- PM.readPrimArray sockets 0+      fd2 <- PM.readPrimArray sockets 1+      pure (Right (fd1, fd2))+    else fmap Left getErrno++{- | Given node and service, which identify an Internet host and a service,+@getaddrinfo()@ returns one or more @addrinfo@ structures. The type of this+wrapper differs slightly from the type of its C counterpart. Remember to call+'uninterruptibleFreeAddressInfo' when finished with the result.+-}+getAddressInfo ::+  -- | Node, identifies an Internet host+  CString ->+  -- | Service+  CString ->+  -- | Hints+  Ptr AddressInfo ->+  IO (Either Errno (Ptr AddressInfo))+getAddressInfo !node !service !hints = do+  resBuf@(MutableByteArray resBuf#) <- PM.newPinnedByteArray (PM.sizeOf (undefined :: Ptr ()))+  c_safe_getaddrinfo node service hints resBuf# >>= \case+    Errno 0 -> do+      res <- PM.readByteArray resBuf 0+      pure (Right res)+    e -> pure (Left e)++{- | Assign a local socket address address to a socket identified by+  descriptor socket that has no local socket address assigned. The+  <http://pubs.opengroup.org/onlinepubs/9699919799/functions/bind.html POSIX specification>+  includes more details. The 'SocketAddress' represents the @sockaddr@ pointer argument, together+  with its @socklen_t@ size, as a byte array. This allows @bind@ to+  be used with @sockaddr@ extensions on various platforms. No special+  preparation is required before calling this function. The author+  believes that it cannot block for a prolonged period of time.+-}+uninterruptibleBind ::+  -- | Socket+  Fd ->+  -- | Socket address, extensible tagged union+  SocketAddress ->+  IO (Either Errno ())+uninterruptibleBind fd (SocketAddress b@(ByteArray b#)) =+  c_bind fd b# (intToCInt (PM.sizeofByteArray b)) >>= errorsFromInt_++{- | Mark the socket as a passive socket, that is, as a socket that+  will be used to accept incoming connection requests using @accept@.+  The <http://pubs.opengroup.org/onlinepubs/9699919799/functions/listen.html POSIX specification>+  includes more details. No special preparation is required before+  calling this function. The author believes that it cannot block+  for a prolonged period of time.+-}+uninterruptibleListen ::+  -- | Socket+  Fd ->+  -- | Backlog+  CInt ->+  IO (Either Errno ())+uninterruptibleListen fd backlog = c_listen fd backlog >>= errorsFromInt_++{- | Connect the socket to the specified socket address.+  The <http://pubs.opengroup.org/onlinepubs/9699919799/functions/connect.html POSIX specification>+  includes more details.+-}+connect ::+  -- | Fd+  Fd ->+  -- | Socket address, extensible tagged union+  SocketAddress ->+  IO (Either Errno ())+connect fd (SocketAddress sockAddr@(ByteArray sockAddr#)) =+  case isByteArrayPinned sockAddr of+    True -> c_safe_connect fd sockAddr# (intToCInt (PM.sizeofByteArray sockAddr)) >>= errorsFromInt_+    False -> do+      let len = PM.sizeofByteArray sockAddr+      x@(MutableByteArray x#) <- PM.newPinnedByteArray len+      PM.copyByteArray x 0 sockAddr 0 len+      c_safe_mutablebytearray_connect fd x# (intToCInt len) >>= errorsFromInt_++{- | Connect the socket to the specified socket address.+  The <http://pubs.opengroup.org/onlinepubs/9699919799/functions/connect.html POSIX specification>+  includes more details. The only sensible way to use this is to+  give a nonblocking socket as the argument.+-}+uninterruptibleConnect ::+  -- | Fd+  Fd ->+  -- | Socket address, extensible tagged union+  SocketAddress ->+  IO (Either Errno ())+uninterruptibleConnect fd (SocketAddress sockAddr@(ByteArray sockAddr#)) =+  c_unsafe_connect fd sockAddr# (intToCInt (PM.sizeofByteArray sockAddr)) >>= errorsFromInt_++uninterruptibleConnectPtr ::+  -- | Fd+  Fd ->+  -- | Socket address+  Ptr a ->+  -- | Size of socket address+  Int ->+  IO (Either Errno ())+uninterruptibleConnectPtr !fd (Ptr sockAddr#) !sz =+  c_unsafe_connect_addr fd sockAddr# (intToCInt sz) >>= errorsFromInt_++{- | Extract the first connection on the queue of pending connections. The+  <http://pubs.opengroup.org/onlinepubs/9699919799/functions/accept.html POSIX specification>+  includes more details. This function\'s type differs slightly from+  the specification:++  > int accept(int socket, struct sockaddr *restrict address, socklen_t *restrict address_len);++  Instead of requiring the caller to prepare buffers through which+  information is returned, this haskell binding to @accept@ prepares+  those buffers internally. This eschews C\'s characteristic buffer-passing+  in favor of the Haskell convention of allocating internally and returning.++  More specifically, this binding lacks an argument corresponding to the+  @sockaddr@ buffer from the specification. That mutable buffer is allocated+  internally, resized and frozen upon a success, and returned along with+  the file descriptor of the accepted socket. The size of this buffer is+  determined by the second argument (maximum socket address size). This+  size argument is also writen to the @address_len@ buffer, which is also+  allocated internally. The size returned through this pointer is used to+  resize the @sockaddr@ buffer, which is then frozen so that an immutable+  'SocketAddress' is returned to the end user.++  For applications uninterested in the peer (described by @sockaddr@),+  POSIX @accept@ allows the null pointer to be passed as both @address@ and+  @address_len@. This behavior is provided by 'accept_'.+-}+accept ::+  -- | Listening socket+  Fd ->+  -- | Maximum socket address size+  CInt ->+  -- | Peer information and connected socket+  IO (Either Errno (CInt, SocketAddress, Fd))+accept !sock !maxSz = do+  sockAddrBuf@(MutableByteArray sockAddrBuf#) <- PM.newPinnedByteArray (cintToInt maxSz)+  lenBuf@(MutableByteArray lenBuf#) <- PM.newPinnedByteArray (PM.sizeOf (undefined :: CInt))+  PM.writeByteArray lenBuf 0 maxSz+  r <- c_safe_accept sock sockAddrBuf# lenBuf#+  if r > (-1)+    then do+      (sz :: CInt) <- PM.readByteArray lenBuf 0+      -- Why copy when we could just shrink? We want to always return+      -- byte arrays that are not explicitly pinned.+      let minSz = min sz maxSz+      x <- PM.newByteArray (cintToInt minSz)+      PM.copyMutableByteArray x 0 sockAddrBuf 0 (cintToInt minSz)+      sockAddr <- PM.unsafeFreezeByteArray x+      pure (Right (sz, SocketAddress sockAddr, r))+    else fmap Left getErrno++{- | See 'accept'. This uses the unsafe FFI. Consequently, it does not+  not need to allocate pinned memory. It only makes sense to call this+  on a nonblocking socket.+-}+uninterruptibleAccept ::+  -- | Listening socket+  Fd ->+  -- | Maximum socket address size+  CInt ->+  -- | Peer information and connected socket+  IO (Either Errno (CInt, SocketAddress, Fd))+uninterruptibleAccept !sock !maxSz = do+  sockAddrBuf@(MutableByteArray sockAddrBuf#) <- PM.newByteArray (cintToInt maxSz)+  lenBuf@(MutableByteArray lenBuf#) <- PM.newByteArray (PM.sizeOf (undefined :: CInt))+  PM.writeByteArray lenBuf 0 maxSz+  r <- c_unsafe_accept sock sockAddrBuf# lenBuf#+  if r > (-1)+    then do+      (sz :: CInt) <- PM.readByteArray lenBuf 0+      if sz < maxSz+        then shrinkMutableByteArray sockAddrBuf (cintToInt sz)+        else pure ()+      sockAddr <- PM.unsafeFreezeByteArray sockAddrBuf+      pure (Right (sz, SocketAddress sockAddr, r))+    else fmap Left getErrno++{- | A variant of 'accept' that does not provide the user with a+  'SocketAddress' detailing the peer.+-}+accept_ ::+  -- | Listening socket+  Fd ->+  -- | Connected socket+  IO (Either Errno Fd)+accept_ sock =+  c_safe_ptr_accept sock nullPtr nullPtr >>= errorsFromFd++{- | Retrieve the locally-bound name of the specified socket. The+  <http://pubs.opengroup.org/onlinepubs/9699919799/functions/accept.html POSIX specification>+  of @getsockname@ includes more details.+-}+uninterruptibleGetSocketName ::+  -- | Socket+  Fd ->+  -- | Maximum socket address size+  CInt ->+  IO (Either Errno (CInt, SocketAddress))+uninterruptibleGetSocketName sock maxSz = do+  sockAddrBuf@(MutableByteArray sockAddrBuf#) <- PM.newByteArray (cintToInt maxSz)+  lenBuf@(MutableByteArray lenBuf#) <- PM.newByteArray (PM.sizeOf (undefined :: CInt))+  PM.writeByteArray lenBuf 0 maxSz+  r <- c_unsafe_getsockname sock sockAddrBuf# lenBuf#+  if r == 0+    then do+      (sz :: CInt) <- PM.readByteArray lenBuf 0+      if sz < maxSz+        then shrinkMutableByteArray sockAddrBuf (cintToInt sz)+        else pure ()+      sockAddr <- PM.unsafeFreezeByteArray sockAddrBuf+      pure (Right (sz, SocketAddress sockAddr))+    else fmap Left getErrno++{- | Retrieve the value for the option specified by the 'Option' argument for+  the socket specified by the 'Fd' argument. The+  <http://pubs.opengroup.org/onlinepubs/9699919799/functions/getsockopt.html POSIX specification>+  of @getsockopt@ includes more details.+-}+uninterruptibleGetSocketOption ::+  -- | Socket+  Fd ->+  -- | Socket level+  Level ->+  OptionName -> -- Option name++  -- | Maximum option value size+  CInt ->+  IO (Either Errno (CInt, OptionValue))+uninterruptibleGetSocketOption sock level optName maxSz = do+  valueBuf@(MutableByteArray valueBuf#) <- PM.newByteArray (cintToInt maxSz)+  lenBuf@(MutableByteArray lenBuf#) <- PM.newByteArray (PM.sizeOf (undefined :: CInt))+  PM.writeByteArray lenBuf 0 maxSz+  r <- c_unsafe_getsockopt sock level optName valueBuf# lenBuf#+  if r == 0+    then do+      (sz :: CInt) <- PM.readByteArray lenBuf 0+      if sz < maxSz+        then shrinkMutableByteArray valueBuf (cintToInt sz)+        else pure ()+      value <- PM.unsafeFreezeByteArray valueBuf+      pure (Right (sz, OptionValue value))+    else fmap Left getErrno++{- | Set the value for the option specified by the 'Option' argument for+  the socket specified by the 'Fd' argument. The+  <http://pubs.opengroup.org/onlinepubs/9699919799/functions/getsockopt.html POSIX specification>+  of @getsockopt@ includes more details. This variant requires that the+  size of the @option_value@+  be the same as the size of 'CInt'. That is, the @option_name@ must+  describe an option that is represented by a C integer. This is a+  common case, so we avoid allocations by reference-passing in C.+-}+uninterruptibleSetSocketOptionInt ::+  -- | Socket+  Fd ->+  -- | Socket level+  Level ->+  -- | Option name+  OptionName ->+  -- | Option value+  CInt ->+  IO (Either Errno ())+uninterruptibleSetSocketOptionInt sock level optName optValue =+  c_unsafe_setsockopt_int sock level optName optValue >>= errorsFromInt_++{- | Set the value for the option specified by the 'Option' argument for+  the socket specified by the 'Fd' argument. The+  <http://pubs.opengroup.org/onlinepubs/9699919799/functions/getsockopt.html POSIX specification>+  of @getsockopt@ includes more details.+-}+uninterruptibleSetSocketOption ::+  -- | Socket+  Fd ->+  -- | Socket level+  Level ->+  -- | Option name+  OptionName ->+  -- | Option value+  Ptr Void ->+  -- | Option value length+  CInt ->+  IO (Either Errno ())+uninterruptibleSetSocketOption sock level optName optValue optLen =+  c_unsafe_setsockopt sock level optName optValue optLen >>= errorsFromInt_++{- | Variant of 'uninterruptibleSetSocketOption' that accepts the option+  as a byte array instead of a pointer into unmanaged memory. The argument+  does not need to be pinned.+-}+uninterruptibleSetSocketOptionByteArray ::+  -- | Socket+  Fd ->+  -- | Socket level+  Level ->+  -- | Option name+  OptionName ->+  -- | Option value+  ByteArray ->+  -- | Option value length+  CInt ->+  IO (Either Errno ())+uninterruptibleSetSocketOptionByteArray sock level optName (ByteArray optVal) optLen =+  c_unsafe_setsockopt_ba sock level optName optVal optLen >>= errorsFromInt_++{- | Send data from a byte array over a network socket. Users+  may specify an offset and a length to send fewer bytes than are+  actually present in the array. Since this uses the safe+  FFI, it allocates a pinned copy of the bytearry if it was not+  already pinned.+-}+sendByteArray ::+  -- | Socket+  Fd ->+  -- | Source byte array+  ByteArray ->+  -- | Offset into source array+  Int ->+  -- | Length in bytes+  CSize ->+  -- | Flags+  MessageFlags 'Send ->+  -- | Number of bytes pushed to send buffer+  IO (Either Errno CSize)+sendByteArray fd b@(ByteArray b#) off len flags =+  if isByteArrayPinned b+    then errorsFromSize =<< c_safe_bytearray_send fd b# off len flags+    else do+      x@(MutableByteArray x#) <- PM.newPinnedByteArray (csizeToInt len)+      PM.copyByteArray x off b 0 (csizeToInt len)+      errorsFromSize =<< c_safe_mutablebytearray_no_offset_send fd x# len flags++{- | Copy and pin a byte array if, it's not already pinned.+pinByteArray :: ByteArray -> IO (Maybe ByteArray)+{\-# INLINE pinByteArray #-\}+pinByteArray byteArray =+  if isByteArrayPinned byteArray+    then+      pure Nothing+    else do+      pinnedByteArray <- PM.newPinnedByteArray len+      PM.copyByteArray pinnedByteArray 0 byteArray 0 len+      r <- PM.unsafeFreezeByteArray pinnedByteArray+      pure (Just r)+  where+    len = PM.sizeofByteArray byteArray+-}++{- | Send two payloads (one from unmanaged memory and one from+managed memory) over a network socket.+-}+uninterruptibleSendMessageA ::+  -- | Socket+  Fd ->+  -- | Source address (payload A)+  Addr ->+  -- | Length in bytes (payload A)+  CSize ->+  -- | Source and offset (payload B)+  MutableByteArrayOffset RealWorld ->+  -- | Length in bytes (payload B)+  CSize ->+  -- | Flags+  MessageFlags 'Send ->+  -- | Number of bytes pushed to send buffer+  IO (Either Errno CSize)+uninterruptibleSendMessageA+  fd+  (Addr addr)+  lenA+  (MutableByteArrayOffset {array, offset})+  lenB+  flags =+    c_unsafe_sendmsg_a fd addr lenA (unMba array) offset lenB flags+      >>= errorsFromSize++{- | Send two payloads (one from managed memory and one from+unmanaged memory) over a network socket.+-}+uninterruptibleSendMessageB ::+  -- | Socket+  Fd ->+  -- | Source and offset (payload B)+  MutableByteArrayOffset RealWorld ->+  -- | Length in bytes (payload B)+  CSize ->+  -- | Source address (payload A)+  Addr ->+  -- | Length in bytes (payload A)+  CSize ->+  -- | Flags+  MessageFlags 'Send ->+  -- | Number of bytes pushed to send buffer+  IO (Either Errno CSize)+uninterruptibleSendMessageB+  fd+  (MutableByteArrayOffset {array, offset})+  lenB+  (Addr addr)+  lenA+  flags =+    c_unsafe_sendmsg_b fd (unMba array) offset lenB addr lenA flags+      >>= errorsFromSize++{- | Send data from a mutable byte array over a network socket. Users+  may specify an offset and a length to send fewer bytes than are+  actually present in the array. Since this uses the safe+  FFI, it allocates a pinned copy of the bytearry if it was not+  already pinned.+-}+sendMutableByteArray ::+  -- | Socket+  Fd ->+  -- | Source byte array+  MutableByteArray RealWorld ->+  -- | Offset into source array+  Int ->+  -- | Length in bytes+  CSize ->+  -- | Flags+  MessageFlags 'Send ->+  -- | Number of bytes pushed to send buffer+  IO (Either Errno CSize)+sendMutableByteArray fd b@(MutableByteArray b#) off len flags =+  if isMutableByteArrayPinned b+    then errorsFromSize =<< c_safe_mutablebytearray_send fd b# off len flags+    else do+      x@(MutableByteArray x#) <- PM.newPinnedByteArray (csizeToInt len)+      PM.copyMutableByteArray x off b 0 (csizeToInt len)+      errorsFromSize =<< c_safe_mutablebytearray_no_offset_send fd x# len flags++{- | Send data from an address over a network socket. This is not guaranteed+  to send the entire length. This uses the safe FFI since+  it may block indefinitely.+-}+send ::+  -- | Connected socket+  Fd ->+  -- | Source address+  Addr ->+  -- | Length in bytes+  CSize ->+  -- | Flags+  MessageFlags 'Send ->+  -- | Number of bytes pushed to send buffer+  IO (Either Errno CSize)+send fd (Addr addr) len flags =+  c_safe_addr_send fd addr len flags >>= errorsFromSize++{- | Send data from an address over a network socket. This uses the unsafe FFI.+  Users of this function should be sure to set flags that prohibit this+  from blocking. On Linux this is accomplished with @O_NONBLOCK@. It is+  often desirable to call 'threadWaitWrite' on a nonblocking socket before+  calling @unsafeSend@ on it.+-}+uninterruptibleSend ::+  -- | Socket+  Fd ->+  -- | Source address+  Addr ->+  -- | Length in bytes+  CSize ->+  -- | Flags+  MessageFlags 'Send ->+  -- | Number of bytes pushed to send buffer+  IO (Either Errno CSize)+uninterruptibleSend fd (Addr addr) len flags =+  c_unsafe_addr_send fd addr len flags >>= errorsFromSize++{- | Send data from a byte array over a network socket. This uses the unsafe FFI;+  considerations pertaining to 'sendUnsafe' apply to this function as well. Users+  may specify a length to send fewer bytes than are actually present in the+  array.+-}+uninterruptibleSendByteArray ::+  -- | Socket+  Fd ->+  -- | Source byte array+  ByteArray ->+  -- | Offset into source array+  Int ->+  -- | Length in bytes+  CSize ->+  -- | Flags+  MessageFlags 'Send ->+  -- | Number of bytes pushed to send buffer+  IO (Either Errno CSize)+uninterruptibleSendByteArray fd (ByteArray b) off len flags =+  c_unsafe_bytearray_send fd b off len flags >>= errorsFromSize++{- | Send data from a mutable byte array over a network socket. This uses the unsafe FFI;+  considerations pertaining to 'sendUnsafe' apply to this function as well. Users+  specify an offset and a length to send fewer bytes than are actually present in the+  array.+-}+uninterruptibleSendMutableByteArray ::+  -- | Socket+  Fd ->+  -- | Source mutable byte array+  MutableByteArray RealWorld ->+  -- | Offset into source array+  Int ->+  -- | Length in bytes+  CSize ->+  -- | Flags+  MessageFlags 'Send ->+  -- | Number of bytes pushed to send buffer+  IO (Either Errno CSize)+uninterruptibleSendMutableByteArray fd (MutableByteArray b) off len flags =+  c_unsafe_mutable_bytearray_send fd b off len flags >>= errorsFromSize++{- | Send data from a byte array over an unconnected network socket.+  This uses the unsafe FFI; considerations pertaining to 'sendToUnsafe'+  apply to this function as well. The offset and length arguments+  cause a slice of the byte array to be sent rather than the entire+  byte array.+-}+uninterruptibleSendToByteArray ::+  -- | Socket+  Fd ->+  -- | Source byte array+  ByteArray ->+  -- | Offset into source array+  Int ->+  -- | Length in bytes+  CSize ->+  -- | Flags+  MessageFlags 'Send ->+  -- | Socket Address+  SocketAddress ->+  -- | Number of bytes pushed to send buffer+  IO (Either Errno CSize)+uninterruptibleSendToByteArray fd (ByteArray b) off len flags (SocketAddress a@(ByteArray a#)) =+  c_unsafe_bytearray_sendto fd b off len flags a# (intToCInt (PM.sizeofByteArray a)) >>= errorsFromSize++{- | Variant of 'uninterruptibleSendToByteArray' that requires+  that @sockaddr_in@ be used as the socket address. This is used to+  avoid allocating a buffer for the socket address when the caller+  knows in advance that they are sending to an IPv4 address.+-}+uninterruptibleSendToInternetByteArray ::+  -- | Socket+  Fd ->+  -- | Source byte array+  ByteArray ->+  -- | Offset into source array+  Int ->+  -- | Length in bytes+  CSize ->+  -- | Flags+  MessageFlags 'Send ->+  -- | Socket Address+  SocketAddressInternet ->+  -- | Number of bytes pushed to send buffer+  IO (Either Errno CSize)+uninterruptibleSendToInternetByteArray fd (ByteArray b) off len flags (SocketAddressInternet {port, address}) =+  c_unsafe_bytearray_sendto_inet fd b off len flags port address >>= errorsFromSize++{- | Variant of 'uninterruptibleSendToByteArray' that requires+  that @sockaddr_in@ be used as the socket address. This is used to+  avoid allocating a buffer for the socket address when the caller+  knows in advance that they are sending to an IPv4 address.+-}+uninterruptibleSendToInternet ::+  -- | Socket+  Fd ->+  -- | Source byte array+  Addr ->+  -- | Length in bytes+  CSize ->+  -- | Flags+  MessageFlags 'Send ->+  -- | Socket Address+  SocketAddressInternet ->+  -- | Number of bytes pushed to send buffer+  IO (Either Errno CSize)+uninterruptibleSendToInternet fd (Addr b) len flags (SocketAddressInternet {port, address}) =+  c_unsafe_addr_sendto_inet fd b len flags port address >>= errorsFromSize++{- | Send data from a mutable byte array over an unconnected network socket.+  This uses the unsafe FFI; concerns pertaining to 'uninterruptibleSend'+  apply to this function as well. The offset and length arguments+  cause a slice of the mutable byte array to be sent rather than the entire+  byte array.+-}+uninterruptibleSendToMutableByteArray ::+  -- | Socket+  Fd ->+  -- | Source byte array+  MutableByteArray RealWorld ->+  -- | Offset into source array+  Int ->+  -- | Length in bytes+  CSize ->+  -- | Flags+  MessageFlags 'Send ->+  -- | Socket Address+  SocketAddress ->+  -- | Number of bytes pushed to send buffer+  IO (Either Errno CSize)+uninterruptibleSendToMutableByteArray fd (MutableByteArray b) off len flags (SocketAddress a@(ByteArray a#)) =+  c_unsafe_mutable_bytearray_sendto fd b off len flags a# (intToCInt (PM.sizeofByteArray a)) >>= errorsFromSize++{- | Variant of 'uninterruptibleSendToMutableByteArray' that requires+  that @sockaddr_in@ be used as the socket address. This is used to+  avoid allocating a buffer for the socket address when the caller+  knows in advance that they are sending to an IPv4 address.+-}+uninterruptibleSendToInternetMutableByteArray ::+  -- | Socket+  Fd ->+  -- | Source byte array+  MutableByteArray RealWorld ->+  -- | Offset into source array+  Int ->+  -- | Length in bytes+  CSize ->+  -- | Flags+  MessageFlags 'Send ->+  -- | Socket Address+  SocketAddressInternet ->+  -- | Number of bytes pushed to send buffer+  IO (Either Errno CSize)+uninterruptibleSendToInternetMutableByteArray fd (MutableByteArray b) off len flags (SocketAddressInternet {port, address}) =+  c_unsafe_mutable_bytearray_sendto_inet fd b off len flags port address >>= errorsFromSize++{- | Receive data into an address from a network socket. This wraps @recv@ using+  the safe FFI. When the returned size is zero, there are no+  additional bytes to receive and the peer has performed an orderly shutdown.+-}+receive ::+  -- | Socket+  Fd ->+  -- | Source address+  Addr ->+  -- | Length in bytes+  CSize ->+  -- | Flags+  MessageFlags 'Receive ->+  IO (Either Errno CSize)+receive fd (Addr addr) len flags =+  c_safe_addr_recv fd addr len flags >>= errorsFromSize++{- | Receive data into a byte array from a network socket. This wraps @recv@ using+  the safe FFI. When the returned size is zero, there are no+  additional bytes to receive and the peer has performed an orderly shutdown.+-}+receiveByteArray ::+  -- | Socket+  Fd ->+  -- | Length in bytes+  CSize ->+  -- | Flags+  MessageFlags 'Receive ->+  IO (Either Errno ByteArray)+receiveByteArray !fd !len !flags = do+  m <- PM.newPinnedByteArray (csizeToInt len)+  let !(Addr addr) = ptrToAddr (PM.mutableByteArrayContents m)+  r <- c_safe_addr_recv fd addr len flags+  if r /= (-1)+    then do+      -- Why copy when we could just shrink? We want to always return+      -- byte arrays that are not explicitly pinned.+      let sz = cssizeToInt r+      x <- PM.newByteArray sz+      PM.copyMutableByteArray x 0 m 0 sz+      a <- PM.unsafeFreezeByteArray x+      pure (Right a)+    else fmap Left getErrno++{- | Receive data into an address from a network socket. This wraps @recv@+  using the unsafe FFI. Users of this function should be sure to set flags+  that prohibit this from blocking. On Linux this is accomplished by setting+  the @MSG_DONTWAIT@ flag and handling the resulting @EAGAIN@ or+  @EWOULDBLOCK@. When the returned size is zero, there are no additional+  bytes to receive and the peer has performed an orderly shutdown.+-}+uninterruptibleReceive ::+  -- | Socket+  Fd ->+  -- | Source address+  Addr ->+  -- | Length in bytes+  CSize ->+  -- | Flags+  MessageFlags 'Receive ->+  IO (Either Errno CSize)+{-# INLINE uninterruptibleReceive #-}+uninterruptibleReceive !fd (Addr !addr) !len !flags =+  c_unsafe_addr_recv fd addr len flags >>= errorsFromSize++{- | Receive data into an address from a network socket. This uses the unsafe+  FFI; considerations pertaining to 'receiveUnsafe' apply to this function+  as well. Users may specify a length to receive fewer bytes than are+  actually present in the mutable byte array.+-}+uninterruptibleReceiveMutableByteArray ::+  -- | Socket+  Fd ->+  -- | Destination byte array+  MutableByteArray RealWorld ->+  -- | Destination offset+  Int ->+  -- | Maximum bytes to receive+  CSize ->+  -- | Flags+  MessageFlags 'Receive ->+  -- | Bytes received into array+  IO (Either Errno CSize)+{-# INLINE uninterruptibleReceiveMutableByteArray #-}+uninterruptibleReceiveMutableByteArray !fd (MutableByteArray !b) !off !len !flags =+  c_unsafe_mutable_byte_array_recv fd b off len flags >>= errorsFromSize++{- | Receive data into an address from an unconnected network socket. This+  uses the unsafe FFI. Users may specify an offset into the destination+  byte array. This function does not resize the buffer.+-}+uninterruptibleReceiveFromMutableByteArray ::+  -- | Socket+  Fd ->+  -- | Destination byte array+  MutableByteArray RealWorld ->+  -- | Destination offset+  Int ->+  -- | Maximum bytes to receive+  CSize ->+  -- | Flags+  MessageFlags 'Receive ->+  -- | Maximum socket address size+  CInt ->+  -- | Remote host, bytes received into array, bytes needed for @addrlen@.+  IO (Either Errno (CInt, SocketAddress, CSize))+{-# INLINE uninterruptibleReceiveFromMutableByteArray #-}+-- GHC does not inline this unless we give it the pragma. We really+-- want this to inline since inlining typically avoids the Left/Right+-- data constructor allocation.+uninterruptibleReceiveFromMutableByteArray !fd (MutableByteArray !b) !off !len !flags !maxSz = do+  -- TODO: We currently allocate one buffer for the size and+  -- one for the peer. We could improve this by allocating+  -- a single buffer instead. We would need to add some+  -- cleverness in the cbits directory.+  sockAddrBuf@(MutableByteArray sockAddrBuf#) <- PM.newByteArray (cintToInt maxSz)+  lenBuf@(MutableByteArray lenBuf#) <- PM.newByteArray (PM.sizeOf (undefined :: CInt))+  PM.writeByteArray lenBuf 0 maxSz+  r <- c_unsafe_mutable_byte_array_recvfrom fd b off len flags sockAddrBuf# lenBuf#+  if r > (-1)+    then do+      (sz :: CInt) <- PM.readByteArray lenBuf 0+      if sz < maxSz+        then shrinkMutableByteArray sockAddrBuf (cintToInt sz)+        else pure ()+      sockAddr <- PM.unsafeFreezeByteArray sockAddrBuf+      pure (Right (sz, SocketAddress sockAddr, cssizeToCSize r))+    else fmap Left getErrno++uninterruptibleReceiveFromInternet ::+  -- | Socket+  Fd ->+  -- | Destination byte array+  Addr ->+  -- | Maximum bytes to receive+  CSize ->+  -- | Flags+  MessageFlags 'Receive ->+  -- | Address+  MutablePrimArrayOffset RealWorld SocketAddressInternet ->+  -- | Number of bytes received into array+  IO (Either Errno CSize)+{-# INLINE uninterruptibleReceiveFromInternet #-}+uninterruptibleReceiveFromInternet+  !fd+  (Addr b)+  !len+  !flags+  (MutablePrimArrayOffset (MutablePrimArray sockAddrBuf) addrOff) =+    c_unsafe_recvfrom_inet_addr fd b len flags sockAddrBuf addrOff+      >>= errorsFromSize++uninterruptibleReceiveFromInternetMutableByteArray ::+  -- | Socket+  Fd ->+  -- | Destination byte array+  MutableByteArrayOffset RealWorld ->+  -- | Maximum bytes to receive+  CSize ->+  -- | Flags+  MessageFlags 'Receive ->+  -- | Address+  MutablePrimArrayOffset RealWorld SocketAddressInternet ->+  -- | Number of bytes received into array+  IO (Either Errno CSize)+{-# INLINE uninterruptibleReceiveFromInternetMutableByteArray #-}+uninterruptibleReceiveFromInternetMutableByteArray+  !fd+  (MutableByteArrayOffset (MutableByteArray b) off)+  !len+  !flags+  (MutablePrimArrayOffset (MutablePrimArray sockAddrBuf) addrOff) =+    c_unsafe_recvfrom_inet fd b off len flags sockAddrBuf addrOff+      >>= errorsFromSize++{- | Receive data into an address from a network socket. This uses the unsafe+  FFI. This does not return the socket address of the remote host that+  sent the packet received.+-}+uninterruptibleReceiveFromMutableByteArray_ ::+  -- | Socket+  Fd ->+  -- | Destination byte array+  MutableByteArray RealWorld ->+  -- | Destination offset+  Int ->+  -- | Maximum bytes to receive+  CSize ->+  -- | Flags+  MessageFlags 'Receive ->+  -- | Number of bytes received into array+  IO (Either Errno CSize)+{-# INLINE uninterruptibleReceiveFromMutableByteArray_ #-}+uninterruptibleReceiveFromMutableByteArray_ !fd (MutableByteArray !b) !off !len !flags =+  c_unsafe_mutable_byte_array_peerless_recvfrom fd b off len flags+    >>= errorsFromSize++{- | Receive data into an address from a network socket. This uses the unsafe+  FFI. This does not return the socket address of the remote host that+  sent the packet received.+-}+uninterruptibleReceiveFrom_ ::+  -- | Socket+  Fd ->+  -- | Destination byte array+  Addr ->+  -- | Maximum bytes to receive+  CSize ->+  -- | Flags+  MessageFlags 'Receive ->+  -- | Number of bytes received into array+  IO (Either Errno CSize)+{-# INLINE uninterruptibleReceiveFrom_ #-}+uninterruptibleReceiveFrom_ !fd (Addr !b) !len !flags =+  c_unsafe_addr_peerless_recvfrom fd b len flags+    >>= errorsFromSize++ptrToAddr :: Ptr Word8 -> Addr+ptrToAddr (Exts.Ptr a) = Addr a++-- | Shutdown a socket. This uses the unsafe FFI.+uninterruptibleShutdown ::+  Fd ->+  ShutdownType ->+  IO (Either Errno ())+uninterruptibleShutdown fd typ =+  c_unsafe_shutdown fd typ >>= errorsFromInt_++errorsFromSize :: CSsize -> IO (Either Errno CSize)+errorsFromSize r =+  if r > (-1)+    then pure (Right (cssizeToCSize r))+    else fmap Left getErrno++errorsFromFd :: Fd -> IO (Either Errno Fd)+errorsFromFd r =+  if r > (-1)+    then pure (Right r)+    else fmap Left getErrno++-- Sometimes, functions that return an int use zero to indicate+-- success and negative one to indicate failure without including+-- additional information in the value.+errorsFromInt_ :: CInt -> IO (Either Errno ())+errorsFromInt_ r =+  if r == 0+    then pure (Right ())+    else fmap Left getErrno++intToCInt :: Int -> CInt+intToCInt = fromIntegral++cintToInt :: CInt -> Int+cintToInt = fromIntegral++csizeToInt :: CSize -> Int+csizeToInt = fromIntegral++cssizeToInt :: CSsize -> Int+cssizeToInt = fromIntegral++-- only call this when it is known that the argument is non-negative+cssizeToCSize :: CSsize -> CSize+cssizeToCSize = fromIntegral++shrinkMutableByteArray :: MutableByteArray RealWorld -> Int -> IO ()+shrinkMutableByteArray (MutableByteArray arr) (I# sz) =+  PM.primitive_ (shrinkMutableByteArray# arr sz)++-- | Convert a 16-bit word from host to network byte order (e.g. @htons@).+hostToNetworkShort :: Word16 -> Word16+hostToNetworkShort = case targetByteOrder of+  BigEndian -> id+  LittleEndian -> byteSwap16++-- | Convert a 16-bit word from network to host byte order (e.g. @ntohs@).+networkToHostShort :: Word16 -> Word16+networkToHostShort = case targetByteOrder of+  BigEndian -> id+  LittleEndian -> byteSwap16++-- | Convert a 32-bit word from host to network byte order (e.g. @htonl@).+hostToNetworkLong :: Word32 -> Word32+hostToNetworkLong = case targetByteOrder of+  BigEndian -> id+  LittleEndian -> byteSwap32++-- | Convert a 32-bit word from network to host byte order (e.g. @ntohl@).+networkToHostLong :: Word32 -> Word32+networkToHostLong = case targetByteOrder of+  BigEndian -> id+  LittleEndian -> byteSwap32++{- $conversion+These functions are used to convert IPv4 addresses and ports between network+byte order and host byte order. They are essential when working with+'SocketAddressInternet'. To avoid getting in the way of GHC compile-time+optimizations, these functions are not actually implemented with FFI+calls to @htonl@ and friends. Rather, they are reimplemented in haskell.+-}++{- $receiveMessage+The function @recvMsg@ presents us with a challenge. Since it uses a+data structure with many nested pointers, we have to use pinned byte+arrays for everything. There is also the difficulty of marshalling+haskell's unlifted array (array of arrays) type into what C's+array of @iovec@. There's the question of the array of @cmsghdr@s.+On top of all of this, we have to answer the question of whether+we want to accept mutable buffer or whether we want to do the+allocations internally (both for the buffers and for the ancilliary+data structurs needed to massage the data into what C expects).++What we do to handle this in offer several variants of @recvmsg@+ending in @A@, @B@, etc.+-}++isByteArrayPinned :: ByteArray -> Bool+{-# INLINE isByteArrayPinned #-}+isByteArrayPinned (ByteArray arr#) =+  Exts.isTrue# (Exts.isByteArrayPinned# arr#)++isMutableByteArrayPinned :: MutableByteArray s -> Bool+{-# INLINE isMutableByteArrayPinned #-}+isMutableByteArrayPinned (MutableByteArray marr#) =+  Exts.isTrue# (Exts.isMutableByteArrayPinned# marr#)++unMba :: MutableByteArray s -> MutableByteArray# s+{-# INLINE unMba #-} unMba (MutableByteArray x) = x
src/Posix/Types.hsc view
@@ -7,18 +7,6 @@   ( CNfds(..)   ) where -import Data.Word--import Foreign.Storable (Storable)-import Data.Bits (FiniteBits,Bits)-#if MIN_VERSION_base(4,14,0) import System.Posix.Types (CNfds(..))-#endif  #include <poll.h>---- This is a compatibility shim for older GHCs-#if !MIN_VERSION_base(4,14,0)-newtype CNfds = CNfds #{type nfds_t}-  deriving newtype (Eq,Real,Integral,Enum,Num,Ord,Storable,FiniteBits,Bits)-#endif
test/Main.hs view
@@ -1,61 +1,56 @@-{-# language BangPatterns #-}-{-# language BinaryLiterals #-}-{-# language LambdaCase #-}-{-# language NamedFieldPuns #-}-{-# language ScopedTypeVariables #-}-{-# language TypeApplications #-}+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE BinaryLiterals #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE NamedFieldPuns #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeApplications #-} -import Control.Concurrent (forkIO)-import Control.Concurrent (threadWaitRead,threadWaitWrite)+import Control.Concurrent (forkIO, threadWaitWrite) import Control.Monad (when)-import Data.Primitive (ByteArray,MutablePrimArray(..),MutableByteArray(..))-import Data.Word (Word32,Word8)-import Foreign.C.Error (Errno,errnoToIOError)-import Foreign.C.Types (CInt,CSize)+import Data.Primitive (ByteArray, MutableByteArray (..), MutablePrimArray (..))+import Data.Word (Word8)+import Foreign.C.Error (Errno, errnoToIOError)+import Foreign.C.Types (CSize) import GHC.Exts (RealWorld) import Numeric (showIntAtBase) import Test.Tasty import Test.Tasty.HUnit -import qualified GHC.Exts as E import qualified Data.Primitive as PM-import qualified Data.Primitive.Unlifted.Array as PM import qualified Data.Primitive.MVar as PM-import qualified Posix.Socket as S-import qualified Linux.Socket as L+import qualified GHC.Exts as E import qualified Linux.Epoll as Epoll+import qualified Posix.Socket as S  main :: IO () main = defaultMain tests  tests :: TestTree-tests = testGroup "tests"-  [ testGroup "posix"-    [ testGroup "sockets"-      [ testCase "A" testSocketsA-      , testCase "B" testSocketsB-      , testCase "C" testSocketsC-      , testCase "D" testSocketsD-      , testCase "E" testSocketsE-      , testCase "F" testSocketsF-      , testCase "G" testSocketsG-      ]-    ]-  , testGroup "linux"-    [ testGroup "sockets"-      [ testCase "A" testLinuxSocketsA-      , testCase "B" testLinuxSocketsB-      , testCase "C" testLinuxSocketsC-      ]-    , testGroup "epoll"-      [ testCase "A" testLinuxEpollA-      ]+tests =+  testGroup+    "tests"+    [ testGroup+        "posix"+        [ testGroup+            "sockets"+            [ testCase "A" testSocketsA+            , testCase "B" testSocketsB+            , testCase "C" testSocketsC+            , testCase "D" testSocketsD+            ]+        ]+    , testGroup+        "linux"+        [ testGroup+            "epoll"+            [ testCase "A" testLinuxEpollA+            ]+        ]     ]-  ]  testSocketsA :: Assertion testSocketsA = do-  (a,b) <- demand =<< S.uninterruptibleSocketPair S.Unix S.datagram S.defaultProtocol+  (a, b) <- demand =<< S.uninterruptibleSocketPair S.Unix S.datagram S.defaultProtocol   m <- PM.newEmptyMVar   _ <- forkIO $ S.receiveByteArray b 5 mempty >>= PM.putMVar m   bytesSent <- demand =<< S.sendByteArray a sample 0 5 mempty@@ -68,26 +63,28 @@   let limit = 10       wordSz = PM.sizeOf (undefined :: Int)       cwordSz = fromIntegral wordSz :: CSize-  (a,b) <- demand =<< S.uninterruptibleSocketPair S.Unix S.datagram S.defaultProtocol+  (a, b) <- demand =<< S.uninterruptibleSocketPair S.Unix S.datagram S.defaultProtocol   lock <- PM.newEmptyMVar-  let go1 !(ix :: Int) !(n :: Int) = if (ix < limit)-        then do-          y <- PM.newByteArray wordSz-          PM.writeByteArray y 0 (1 + n)-          z <- PM.unsafeFreezeByteArray y-          oneWord =<< demand =<< S.sendByteArray b z 0 cwordSz mempty-          x <- demand =<< S.receiveByteArray b cwordSz mempty-          go1 (ix + 1) (PM.indexByteArray x 0)-        else pure n-      go2 !(ix :: Int) = if (ix < limit)-        then do-          x <- demand =<< S.receiveByteArray a cwordSz mempty-          y <- PM.newByteArray wordSz-          PM.writeByteArray y 0 (1 + PM.indexByteArray x 0 :: Int) -          z <- PM.unsafeFreezeByteArray y-          oneWord =<< demand =<< S.sendByteArray a z 0 cwordSz mempty-          go2 (ix + 1)-        else PM.putMVar lock ()+  let go1 !(ix :: Int) !(n :: Int) =+        if (ix < limit)+          then do+            y <- PM.newByteArray wordSz+            PM.writeByteArray y 0 (1 + n)+            z <- PM.unsafeFreezeByteArray y+            oneWord =<< demand =<< S.sendByteArray b z 0 cwordSz mempty+            x <- demand =<< S.receiveByteArray b cwordSz mempty+            go1 (ix + 1) (PM.indexByteArray x 0)+          else pure n+      go2 !(ix :: Int) =+        if (ix < limit)+          then do+            x <- demand =<< S.receiveByteArray a cwordSz mempty+            y <- PM.newByteArray wordSz+            PM.writeByteArray y 0 (1 + PM.indexByteArray x 0 :: Int)+            z <- PM.unsafeFreezeByteArray y+            oneWord =<< demand =<< S.sendByteArray a z 0 cwordSz mempty+            go2 (ix + 1)+          else PM.putMVar lock ()   _ <- forkIO (go2 0)   r <- go1 0 0   PM.takeMVar lock@@ -95,7 +92,7 @@  testSocketsC :: Assertion testSocketsC = do-  (a,b) <- demand =<< S.uninterruptibleSocketPair S.Unix S.datagram S.defaultProtocol+  (a, b) <- demand =<< S.uninterruptibleSocketPair S.Unix S.datagram S.defaultProtocol   m <- PM.newEmptyMVar   _ <- forkIO $ S.receiveByteArray a 5 mempty >>= PM.putMVar m   bytesSent <- demand =<< S.sendByteArray b sample 0 5 mempty@@ -105,175 +102,33 @@  testSocketsD :: Assertion testSocketsD = do-  (a,b) <- demand =<< S.uninterruptibleSocketPair S.Unix S.datagram S.defaultProtocol+  (a, b) <- demand =<< S.uninterruptibleSocketPair S.Unix S.datagram S.defaultProtocol   _ <- forkIO $ do     bytesSent <- demand =<< S.sendByteArray b sample 0 5 mempty     when (bytesSent /= 5) (fail "testSocketsD: bytesSent was wrong")   actual <- demand =<< S.receiveByteArray a 5 mempty   sample @=? actual -testSocketsE :: Assertion-testSocketsE = do-  (a,b) <- demand =<< S.uninterruptibleSocketPair S.Unix S.datagram S.defaultProtocol-  _ <- forkIO $ do-    threadWaitWrite b-    bytesSent <- demand =<< S.uninterruptibleSendByteArray b sample 0 5 mempty-    when (bytesSent /= 5) (fail "testSocketsE: bytesSent was wrong")-  threadWaitRead a-  actual <- demand =<< S.uninterruptibleReceiveMessageA a 3 10 mempty-  (5,E.fromList [E.fromList [1,2,3],E.fromList [4,5]]) @=? actual--testSocketsF :: Assertion-testSocketsF = do-  a <- demand =<< S.uninterruptibleSocket S.Internet S.datagram S.defaultProtocol-  demand =<< S.uninterruptibleBind a (S.encodeSocketAddressInternet (S.SocketAddressInternet {S.port = 0, S.address = localhost}))-  (expectedSzA,expectedSockAddrA) <- demand =<< S.uninterruptibleGetSocketName a 128-  when (expectedSzA > 128) (fail "testSocketsF: bad socket address size for socket A")-  portA <- case S.decodeSocketAddressInternet expectedSockAddrA of-    Nothing -> fail "testSocketsF: not a sockaddr_in"-    Just (S.SocketAddressInternet {S.port}) -> pure port-  b <- demand =<< S.uninterruptibleSocket S.Internet S.datagram S.defaultProtocol-  demand =<< S.uninterruptibleBind b (S.encodeSocketAddressInternet (S.SocketAddressInternet {S.port = 0, S.address = localhost}))-  threadWaitWrite b-  bytesSent <- demand =<< S.uninterruptibleSendToByteArray b sample 0 5 mempty (S.encodeSocketAddressInternet (S.SocketAddressInternet {S.port = portA, S.address = localhost}))-  when (bytesSent /= 5) (fail "testSocketsF: bytesSent was wrong")-  threadWaitRead a-  actual <- demand =<< S.uninterruptibleReceiveMessageB a 5 2 mempty 128-  (expectedSzB,expectedSockAddrB) <- demand =<< S.uninterruptibleGetSocketName b 128-  when (expectedSzB > 128) (fail "testSocketsF: bad socket address size for socket B")-  (expectedSzB,expectedSockAddrB,5,E.fromList [sample]) @=? actual--testSocketsG :: Assertion-testSocketsG = do-  (a,b) <- demand =<< S.uninterruptibleSocketPair S.Unix S.datagram S.defaultProtocol-  _ <- forkIO $ do-    bytesSent <- demand =<< S.writeVector b-      ( E.fromList-        [ E.fromList (enumFromTo (1 :: Word8) 6)-        , E.fromList (enumFromTo (7 :: Word8) 9)-        ]-      )-    when (bytesSent /= 9) (fail "testSocketsG: bytesSent was wrong")-  actual <- demand =<< S.receiveByteArray a 9 mempty-  E.fromList (enumFromTo (1 :: Word8) 9) @=? actual--testLinuxSocketsA :: Assertion-testLinuxSocketsA = do-  (a,b) <- demand =<< S.uninterruptibleSocketPair S.Unix S.datagram S.defaultProtocol-  threadWaitWrite b-  bytesSent1 <- demand =<< S.uninterruptibleSendByteArray b sample 0 5 mempty-  threadWaitWrite b-  bytesSent2 <- demand =<< S.uninterruptibleSendByteArray b sample2 0 4 mempty-  when (bytesSent1 /= 5) (fail "testLinuxSocketsA: bytesSent1 was wrong")-  when (bytesSent2 /= 4) (fail "testLinuxSocketsA: bytesSent2 was wrong")-  threadWaitRead a-  actual <- demand =<< L.uninterruptibleReceiveMultipleMessageA a 6 3 L.dontWait-  (5,E.fromList [sample,sample2]) @=? actual--testLinuxSocketsB :: Assertion-testLinuxSocketsB = do-  a <- demand =<< S.uninterruptibleSocket S.Internet S.datagram S.defaultProtocol-  demand =<< S.uninterruptibleBind a (S.encodeSocketAddressInternet (S.SocketAddressInternet {S.port = 0, S.address = localhost}))-  (expectedSzA,expectedSockAddrA) <- demand-    =<< S.uninterruptibleGetSocketName a 128-  when (expectedSzA /= S.sizeofSocketAddressInternet)-    (fail "testLinixSocketsB: bad socket address size for socket A")-  portA <- case S.decodeSocketAddressInternet expectedSockAddrA of-    Nothing -> fail "testLinixSocketsB: not a sockaddr_in"-    Just (S.SocketAddressInternet {S.port}) -> pure port-  b <- demand =<< S.uninterruptibleSocket S.Internet S.datagram S.defaultProtocol-  demand =<< S.uninterruptibleBind b-    (S.encodeSocketAddressInternet $ S.SocketAddressInternet-      { S.port = 0-      , S.address = localhost-      }-    )-  threadWaitWrite b-  bytesSent1 <- demand =<< S.uninterruptibleSendToByteArray b sample 0 5 mempty-    (S.encodeSocketAddressInternet (S.SocketAddressInternet {S.port = portA, S.address = localhost}))-  when (bytesSent1 /= 5)-    (fail "testLinixSocketsB: bytesSent1 was wrong")-  threadWaitWrite b-  bytesSent2 <- demand =<< S.uninterruptibleSendToByteArray b sample2 0 4 mempty-    (S.encodeSocketAddressInternet (S.SocketAddressInternet {S.port = portA, S.address = localhost}))-  when (bytesSent2 /= 4)-    (fail "testLinixSocketsB: bytesSent2 was wrong")-  threadWaitRead a-  actual <- demand-    =<< L.uninterruptibleReceiveMultipleMessageB a S.sizeofSocketAddressInternet 6 3 L.dontWait-  (expectedSzB,S.SocketAddress sabytesB) <- demand =<< S.uninterruptibleGetSocketName b 128-  when (expectedSzB /= S.sizeofSocketAddressInternet)-    (fail "testLinixSocketsB: bad socket address size for socket B")-  (0,sabytesB <> sabytesB,5,E.fromList [sample,sample2]) @=? actual--testLinuxSocketsC :: Assertion-testLinuxSocketsC = do-  a <- demand =<< S.uninterruptibleSocket S.Internet S.datagram S.defaultProtocol-  demand =<< S.uninterruptibleBind a (S.encodeSocketAddressInternet (S.SocketAddressInternet {S.port = 0, S.address = localhost}))-  (expectedSzA,expectedSockAddrA) <- demand-    =<< S.uninterruptibleGetSocketName a 128-  when (expectedSzA /= S.sizeofSocketAddressInternet)-    (fail "testLinuxSocketsC: bad socket address size for socket A")-  portA <- case S.decodeSocketAddressInternet expectedSockAddrA of-    Nothing -> fail "testLinuxSocketsC: not a sockaddr_in"-    Just (S.SocketAddressInternet {S.port}) -> pure port-  b <- demand =<< S.uninterruptibleSocket S.Internet S.datagram S.defaultProtocol-  demand =<< S.uninterruptibleBind b-    (S.encodeSocketAddressInternet $ S.SocketAddressInternet-      { S.port = 0-      , S.address = localhost-      }-    )-  threadWaitWrite b-  bytesSent1 <- demand =<< S.uninterruptibleSendToByteArray b sample 0 5 mempty-    (S.encodeSocketAddressInternet (S.SocketAddressInternet {S.port = portA, S.address = localhost}))-  when (bytesSent1 /= 5)-    (fail "testLinuxSocketsC: bytesSent1 was wrong")-  threadWaitWrite b-  bytesSent2 <- demand =<< S.uninterruptibleSendToByteArray b sample2 0 4 mempty-    (S.encodeSocketAddressInternet (S.SocketAddressInternet {S.port = portA, S.address = localhost}))-  when (bytesSent2 /= 4)-    (fail "testLinuxSocketsC: bytesSent2 was wrong")-  threadWaitRead a-  lens <- PM.newPrimArray 2-  addrs <- PM.newPrimArray 2-  payloadsMut <- PM.unsafeNewUnliftedArray 2-  PM.newByteArray 6 >>= PM.writeUnliftedArray payloadsMut 0-  PM.newByteArray 6 >>= PM.writeUnliftedArray payloadsMut 1-  msgCount <- demand =<< L.uninterruptibleReceiveMultipleMessageC a lens addrs payloadsMut 2 L.dontWait-  when (msgCount /= 2) (fail "wrong number of messages")-  addrsFrozen <- PM.unsafeFreezePrimArray addrs-  payloads <- PM.unsafeFreezeUnliftedArray payloadsMut-  len0 <- PM.readPrimArray lens 0-  len1 <- PM.readPrimArray lens 1-  buf0 <- PM.unsafeFreezeByteArray-    =<< PM.resizeMutableByteArray (PM.indexUnliftedArray payloads 0) (fromIntegral @CInt @Int len0)-  buf1 <- PM.unsafeFreezeByteArray-    =<< PM.resizeMutableByteArray (PM.indexUnliftedArray payloads 1) (fromIntegral @CInt @Int len1)-  (expectedSzB,S.SocketAddress sabytesB) <- demand =<< S.uninterruptibleGetSocketName b 128-  when (expectedSzB /= S.sizeofSocketAddressInternet)-    (fail "testLinuxSocketsC: bad socket address size for socket B")-  let primSockAddr = case sabytesB of PM.ByteArray x -> PM.PrimArray x-  (primSockAddr <> primSockAddr,E.fromList [sample,sample2]) @=? (addrsFrozen,[buf0,buf1])- -- This test opens two datagram sockets and send a message from each -- one to the other. Then it checks that epoll's event-triggered -- interface correctly notifies the user about the read-readiness -- that has happened. testLinuxEpollA :: Assertion testLinuxEpollA = do-  (a,b) <- demand =<< S.uninterruptibleSocketPair S.Unix S.datagram S.defaultProtocol+  (a, b) <- demand =<< S.uninterruptibleSocketPair S.Unix S.datagram S.defaultProtocol   epfd <- demand =<< Epoll.uninterruptibleCreate 1   reg <- PM.newPrimArray 1-  PM.writePrimArray reg 0 $ Epoll.Event-    { Epoll.events = Epoll.input <> Epoll.edgeTriggered-    , Epoll.payload = a-    }+  PM.writePrimArray reg 0 $+    Epoll.Event+      { Epoll.events = Epoll.input <> Epoll.edgeTriggered+      , Epoll.payload = a+      }   demand =<< Epoll.uninterruptibleControlMutablePrimArray epfd Epoll.add a reg-  PM.writePrimArray reg 0 $ Epoll.Event-    { Epoll.events = Epoll.input <> Epoll.edgeTriggered-    , Epoll.payload = b-    }+  PM.writePrimArray reg 0 $+    Epoll.Event+      { Epoll.events = Epoll.input <> Epoll.edgeTriggered+      , Epoll.payload = b+      }   demand =<< Epoll.uninterruptibleControlMutablePrimArray epfd Epoll.add b reg   threadWaitWrite b   bytesSentB <- demand =<< S.uninterruptibleSendByteArray b sample 0 5 mempty@@ -287,13 +142,13 @@   when (evCount /= 2) (fail ("testLinuxEpollA: evCount was " ++ show evCount))   r <- case () of     _ -> do-      Epoll.Event{Epoll.events,Epoll.payload} <- PM.readPrimArray evs 0+      Epoll.Event {Epoll.events, Epoll.payload} <- PM.readPrimArray evs 0       when (payload /= a && payload /= b) (fail ("testLinuxEpollA: payload x was " ++ show payload))       let Epoll.Events e = events       when (not (Epoll.containsAnyEvents events Epoll.input)) $ do         fail ("testLinuxEpollA: events x bitmask " ++ showIntAtBase 2 binChar e " missing EPOLLIN")       pure payload-  Epoll.Event{Epoll.events,Epoll.payload} <- PM.readPrimArray evs 1+  Epoll.Event {Epoll.events, Epoll.payload} <- PM.readPrimArray evs 1   when (payload == r) (fail ("testLinuxEpollA: same payload " ++ show payload ++ " for both events"))   when (payload /= a && payload /= b) (fail ("testLinuxEpollA: payload y was " ++ show payload))   let Epoll.Events e = events@@ -311,25 +166,20 @@ loadGarbage (MutablePrimArray x) = do   let arr = MutableByteArray x       go :: Int -> IO ()-      go !ix = if ix > (-1)-        then do-          PM.writeByteArray arr ix ((0b01010101 :: Word8) + fromIntegral ix)-          go (ix - 1)-        else pure ()+      go !ix =+        if ix > (-1)+          then do+            PM.writeByteArray arr ix ((0b01010101 :: Word8) + fromIntegral ix)+            go (ix - 1)+          else pure ()   n <- PM.getSizeofMutableByteArray arr   go (n - 1)  sample :: ByteArray-sample = E.fromList [1,2,3,4,5]--sample2 :: ByteArray-sample2 = E.fromList [6,7,8,9]+sample = E.fromList [1, 2, 3, 4, 5]  demand :: Either Errno a -> IO a demand = either (\e -> ioError (errnoToIOError "test" e Nothing Nothing)) pure-  + oneWord :: CSize -> IO () oneWord x = if x == fromIntegral (PM.sizeOf (undefined :: Int)) then pure () else fail "expected one machine word"--localhost :: Word32-localhost = S.hostToNetworkLong 2130706433