packages feed

sockets-0.6.1.0: src-internal/Socket.hs

{-# language BangPatterns #-}
{-# language DataKinds #-}
{-# language DeriveAnyClass #-}
{-# language DerivingStrategies #-}
{-# language DuplicateRecordFields #-}
{-# language GADTs #-}
{-# language KindSignatures #-}
{-# language StandaloneDeriving #-}

module Socket
  ( SocketUnrecoverableException(..)
  , SocketException(..)
  , BindException(..)
  , Direction(..)
  , Connectedness(..)
  , Pinnedness(..)
  , Family(..)
  , Version(..)
  , Interruptibility(..)
  , Forkedness(..)
  , cgetsockname 
  , cgetsockopt
  , cclose 
  , crecv 
  , crecvfrom
  , cshutdown
  , negativeSliceLength
  , nonInternetSocketFamily
  , functionWithAccepted
  , functionWithConnection
  , functionWithListener
  , functionWithSocket
  , functionGracefulClose
  , socketAddressSize
  ) where

import Control.Exception (Exception(..))
import Data.Kind (Type)
import Data.Typeable (Typeable)
import Foreign.C.Types (CInt)

import qualified Data.List as L

data Direction = Send | Receive

data Connectedness = Connected | Unconnected

-- | This is used as a phantom type to distinguish
-- between pinned and unpinned memory. The distinction
-- drawn here concerns the manner in which the user
-- requested the byte array. Byte arrays resulting
-- from newPinnedByteArray# are considered 'Pinned'
-- while those resulting from newByteArray# are
-- considered 'Unpinned'. Even if the runtime decides
-- to pin a byte array requested by newByteArray#
-- (e.g. because it is larger than 3KB), it is
-- considered 'Unpinned' by this classification.
data Pinnedness = Pinned | Unpinned

data Family = Internet Version | Unix

data Version = V4 | V6

data Interruptibility = Interruptible | Uninterruptible

data Forkedness = Forked | Unforked

data SocketException :: Type where
  -- | A limit on the number of open file descriptors has been reached.
  --   This could be the per-process limit or the system limit.
  --   (@EMFILE@ and @ENFILE@)
  SocketFileDescriptorLimit :: SocketException

deriving stock instance Show SocketException
deriving stock instance Eq SocketException
deriving anyclass instance Exception SocketException

-- | Recoverable exceptions that happen when establishing stream listeners
-- or opening datagram sockets.
--
-- ==== __Discussion__
--
-- The recoverable exceptions that we encounter with stream sockets (established
-- with @socket@-@bind@-@listen@) and datagram sockets (established with
-- @socket@-@bind@) are the exact same exceptions. Consequently, we reuse
-- the same type in both case.
data BindException :: Family -> Type where
  -- | The address is protected, and the user is not the superuser. This most
  --   commonly happens when trying to bind to a port below 1024. On Linux,
  --   When it is necessary to bind to such a port on Linux, consider using the
  --   <http://man7.org/linux/man-pages/man7/capabilities.7.html CAP_NET_BIND_SERVICE>
  --   capability instead of running the process as root. (@EACCES@)
  BindPermissionDenied :: BindException f
  -- | The given address is already in use. This can also happen if the
  --   address was recently bound to and closed. As mandated by
  --   <https://tools.ietf.org/html/rfc793 RFC 793>, such a socket remains
  --   in the @TIME-WAIT@ state for a while (commonly 30 to 120 seconds),
  --   and no new socket may be bound to the address during this period.
  --   (@EADDRINUSE@ with specified port)
  BindAddressInUse :: BindException f
  -- | The port number was specified as zero, but upon attempting to
  --   bind to an ephemeral port, it was determined that all port numbers
  --   numbers in the ephemeral port range are currently in use.
  --   (@EADDRINUSE@ with unspecified port)
  BindEphemeralPortsExhausted :: BindException ('Internet v)
  -- | A limit on the number of open file descriptors has been reached.
  --   This could be the per-process limit or the system limit.
  --   (@EMFILE@ and @ENFILE@)
  BindFileDescriptorLimit :: BindException f

deriving stock instance Show (BindException f)
deriving stock instance Eq (BindException f)
deriving anyclass instance Typeable f => Exception (BindException f)


data SocketUnrecoverableException = SocketUnrecoverableException
  { modules :: String
  , function :: String
  , description :: [String]
  }
  deriving stock (Show,Eq)

instance Exception SocketUnrecoverableException where
  displayException (SocketUnrecoverableException m f d) =
    m ++ "." ++ f ++ ": [" ++ L.intercalate "," d ++ "]"

cgetsockname :: String
cgetsockname = "getsockname"

cgetsockopt :: String
cgetsockopt = "getsockopt"

cclose :: String
cclose = "getsockname"

crecv :: String
crecv = "recv"

crecvfrom :: String
crecvfrom = "recvfrom"

cshutdown :: String
cshutdown = "shutdown"

functionGracefulClose :: String
functionGracefulClose = "gracefulClose"

nonInternetSocketFamily :: String
nonInternetSocketFamily = "non-internet socket family"

negativeSliceLength :: String
negativeSliceLength = "negative slice length"

functionWithAccepted :: String
functionWithAccepted = "withAccepted"

functionWithConnection :: String
functionWithConnection = "withConnection"

functionWithListener :: String
functionWithListener = "withListener"

functionWithSocket :: String
functionWithSocket = "withSocket"

socketAddressSize :: String
socketAddressSize = "socket address size"