HORIZON HASKELLDocslts/ghc-9.14.xd82dee82026-10-12Search names, modules, packages, or :: a typeCtrl K

GHC 9.14.1 · lts/ghc-9.14.x · d82dee8 · 2026-10-12

Modulesocket-0.8.3.0Haskell2010

System.Socket

{-# LANGUAGE OverloadedStrings #-}
module Main where

import Control.Exception ( bracket, catch )
import Control.Monad ( forever )

import System.Socket
import System.Socket.Family.Inet6
import System.Socket.Type.Stream
import System.Socket.Protocol.TCP

main :: IO ()
main = bracket
  ( socket :: IO (Socket Inet6 Stream TCP) )
  ( \s-> do
    close s
    putStrLn "Listening socket closed."
  )
  ( \s-> do
    setSocketOption s (ReuseAddress True)
    setSocketOption s (V6Only False)
    bind s (SocketAddressInet6 inet6Any 8080 0 0)
    listen s 5
    putStrLn "Listening socket ready..."
    forever $ acceptAndHandle s `catch` \e-> print (e :: SocketException)
  )

acceptAndHandle :: Socket Inet6 Stream TCP -> IO ()
acceptAndHandle s = bracket
  ( accept s )
  ( \(p, addr)-> do
    close p
    putStrLn $ "Closed connection to " ++ show addr
  )
  ( \(p, addr)-> do
    putStrLn $ "Accepted connection from " ++ show addr
    sendAll p "Hello world!" msgNoSignal
  )
  • 11 types
  • 6 classes
  • 73 values
  • Packagesocket-0.8.3.0
  • Exports91
  • LanguageHaskell2010
  • LicenceMIT
  • SourceSocket.hsc

Socket

2 declarations
newtypenewtype Socket f t p
#

A generic socket type. Use socket to create a new socket.

The socket is just an MVar-wrapped file descriptor. The Socket constructor is exported trough the unsafe module in order to make this library easily extensible, but it is usually not necessary nor advised to work directly on the file descriptor. If you do, the following rules must be obeyed:

  • Make sure not to deadlock. Use withMVar or similar.

  • The lock must not be held during a blocking call. This would make it impossible to send and receive simultaneously or to close the socket.

  • The lock must be held when calling operations that use the file descriptor. Otherwise the socket might get closed or even reused by another thread/capability which might result in reading from or writing on a totally different socket. This is a security nightmare!

  • The socket is non-blocking and all the code relies on that assumption. You need to use GHC's eventing mechanism primitives to block until something happens. The former rules forbid to use GHC.Conc.threadWaitRead as it does not separate between registering the file descriptor (for which the lock must be held) and the actual waiting (for which you must not hold the lock). Also see this thread and read the library code to see how the problem is currently circumvented.

familydata family SocketAddress f
#

The SocketAddress type is a data family. This allows to provide different data constructors depending on the socket family without knowing all of them in advance or the need to extend this core library.

SocketAddressInet  inetLoopback  8080     :: SocketAddress Inet
SocketAddressInet6 inet6Loopback 8080 0 0 :: SocketAddress Inet6
Instances8Eq, Show, Storable, SocketAddress, …

Family

classclass Storable (SocketAddress f) => Family f where
#

The address Family determines the network protocol to use.

The most common address families are Inet (IPv4) and Inet6 (IPv6).

Associated types

  • data family SocketAddress f

    The SocketAddress type is a data family. This allows to provide different data constructors depending on the socket family without knowing all of them in advance or the need to extend this core library.

    SocketAddressInet  inetLoopback  8080     :: SocketAddress Inet
    SocketAddressInet6 inet6Loopback 8080 0 0 :: SocketAddress Inet6

Methods

  • familyNumber :: f -> CInt

    The number designating this Family on the specific platform. This method is only exported for implementing extension libraries.

    This function shall yield the values of constants like AF_INET, AF_INET6 etc.

Instances2Family
  • Family InetDefined in socket-0.8.3.0 · System.Socket.Family.Inet
  • Family Inet6Defined in socket-0.8.3.0 · System.Socket.Family.Inet6

Type

classclass Type t where
#

The Type determines properties of the transport layer and the semantics of basic socket operations.

The instances supplied by this library are System.Socket.Type.Raw (no transport layer), System.Socket.Type.Stream (for unframed binary streams, e.g. System.Socket.Protocol.TCP), System.Socket.Type.Datagram (for datagrams of limited length, e.g. System.Socket.Protocol.UDP) and System.Socket.Type.SequentialPacket (for framed messages of arbitrary length, e.g. System.Socket.Protocol.SCTP).

Methods

  • typeNumber :: t -> CInt

    This number designates this Type on the specific platform. This method is only exported for implementing extension libraries.

    The function shall yield the values of constants like SOCK_STREAM, SOCK_DGRAM etc.

Instances4Type
  • Type DatagramDefined in socket-0.8.3.0 · System.Socket.Type.Datagram
  • Type RawDefined in socket-0.8.3.0 · System.Socket.Type.Raw
  • Type SequentialPacketDefined in socket-0.8.3.0 · System.Socket.Type.SequentialPacket
  • Type StreamDefined in socket-0.8.3.0 · System.Socket.Type.Stream

Protocol

classclass Protocol p where
#

The Protocol determines the transport protocol to use.

Use System.Socket.Protocol.Default to let the operating system choose a transport protocol compatible with the socket's Type.

Methods

  • protocolNumber :: p -> CInt

    This number designates this Protocol on the specific platform. This method is only exported for implementing extension libraries.

    The function shall yield the values of constants like IPPROTO_TCP, IPPROTO_UDP etc.

Instances3Protocol
  • Protocol DefaultDefined in socket-0.8.3.0 · System.Socket.Protocol.Default
  • Protocol TCPDefined in socket-0.8.3.0 · System.Socket.Protocol.TCP
  • Protocol UDPDefined in socket-0.8.3.0 · System.Socket.Protocol.UDP

Operations

0 declarations

socket

valuesocket :: (Family f, Type t, Protocol p) => IO (Socket f t p)
#

Creates a new socket.

Whereas the underlying POSIX socket operation takes 3 parameters, this library encodes this information in the type variables. This rules out several kinds of errors and especially simplifies the handling of addresses (by using associated data families). Examples:

-- create an IPv4-UDP-datagram socket
sock <- socket :: IO (Socket Inet Datagram UDP)
-- create an IPv6-TCP-streaming socket
sock6 <- socket :: IO (Socket Inet6 Stream TCP)
-- create an IPv6-streaming socket with default protocol (usually TCP)
sock6 <- socket :: IO (Socket Inet6 Strem Default)
  • This operation sets up a finalizer that automatically closes the socket when the garbage collection decides to collect it. This is just a fail-safe. You might still run out of file descriptors as there's no guarantee about when the finalizer is run. You're advised to manually close the socket when it's no longer needed. If possible, use bracket to reliably close the socket descriptor on exception or regular termination of your computation:

result <- bracket (socket :: IO (Socket Inet6 Stream TCP)) close $ \sock-> do
  somethingWith sock -- your computation here
  return somethingelse
  • This operation configures the socket non-blocking to work seamlessly with the runtime system's event notification mechanism.

  • This operation can safely deal with asynchronous exceptions without leaking file descriptors.

  • This operation throws SocketExceptions. Consult your man socket for details and specific errors.

connect

valueconnect :: Family f => Socket f t p -> SocketAddress f -> IO ()
#

Connects to a remote address.

  • This operation returns as soon as a connection has been established (as if the socket were blocking). The connection attempt has either failed or succeeded after this operation threw an exception or returned.

  • The operation throws SocketExceptions. Calling connect on a closed socket throws eBadFileDescriptor even if the former file descriptor has been reassigned.

bind

valuebind :: Family f => Socket f t p -> SocketAddress f -> IO ()
#

Bind a socket to an address.

  • Calling bind on a closed socket throws eBadFileDescriptor even if the former file descriptor has been reassigned.

  • It is assumed that bind never blocks and therefore eInProgress, eAlready and eInterrupted don't occur. This assumption is supported by the fact that the Linux manpage doesn't mention any of these errors, the Posix manpage doesn't mention the last one and even MacOS' implementation will never fail with any of these when the socket is configured non-blocking as argued here.

  • This operation throws SocketExceptions. Consult your man page for details and specific errnos.

listen

valuelisten :: Socket f t p -> Int -> IO ()
#

Starts listening and queueing connection requests on a connection-mode socket. The second parameter determines the backlog size.

  • Calling listen on a closed socket throws eBadFileDescriptor even if the former file descriptor has been reassigned.

  • The second parameter is called backlog and sets a limit on how many unaccepted connections the transport implementation shall queue. A value of 0 leaves the decision to the implementation.

  • This operation throws SocketExceptions. Consult your man listen for details and specific errors.

accept

valueaccept :: Family f => Socket f t p -> IO (Socket f t p, SocketAddress f)
#

Accept a new connection.

  • Calling accept on a closed socket throws eBadFileDescriptor even if the former file descriptor has been reassigned.

  • This operation configures the new socket non-blocking. It uses accept4 (when available) in order to accept and set the socket non-blocking with a single system call.

  • This operation sets up a finalizer for the new socket that automatically closes the new socket when the garbage collection decides to collect it. This is just a fail-safe. You might still run out of file descriptors as there's no guarantee about when the finalizer is run. You're advised to manually close the socket when it's no longer needed.

  • This operation throws SocketExceptions.

  • This operation catches eAgain, eWouldBlock and eInterrupted internally and retries automatically.

send, sendTo

valuesend :: Socket f t p -> ByteString -> MessageFlags -> IO Int
#

Send data.

  • Calling send on a closed socket throws eBadFileDescriptor even if the former file descriptor has been reassigned.

  • The operation returns the number of bytes sent. On System.Socket.Type.Datagram and System.Socket.Type.SequentialPacket sockets certain assurances on atomicity exist and eAgain or eWouldBlock are thrown until the whole message would fit into the send buffer.

  • This operation throws SocketExceptions. Consult man send for details and specific errors.

  • eAgain, eWouldBlock and eInterrupted and handled internally and won't be thrown. For performance reasons the operation first tries a write on the socket and then waits when it got eAgain or eWouldBlock.

receive, receiveFrom

valuereceive :: Socket f t p -> Int -> MessageFlags -> IO ByteString
#

Receive data.

  • The operation takes a buffer size in bytes a first parameter which limits the maximum length of the returned ByteString.

  • When an empty ByteString is returned this usally (protocol specific) means that the peer gracefully closed the connection. The user is advised to check for and handle this case.

  • Calling receive on a closed socket throws eBadFileDescriptor even if the former file descriptor has been reassigned.

  • This operation throws SocketExceptions. Consult man recv for details and specific errors.

  • eAgain, eWouldBlock and eInterrupted and handled internally and won't be thrown. For performance reasons the operation first tries a read on the socket and then waits when it got eAgain or eWouldBlock until the socket is signaled to be readable.

close

valueclose :: Socket f t p -> IO ()
#

Closes a socket.

  • This operation is idempotent and thus can be performed more than once without throwing an exception. If it throws an exception it is presumably a not recoverable situation and the process should exit.

  • This operation does not block.

  • This operation wakes up all threads that are currently blocking on this socket. All other threads are guaranteed to not block on operations on this socket in the future. Threads that perform operations other than close on this socket will fail with eBadFileDescriptor after the socket has been closed (close replaces the Fd in the MVar with -1 to reliably avoid use-after-free situations).

  • This operation potentially throws SocketExceptions (only EIO is documented). eInterrupted is catched internally and retried automatically, so won't be thrown.

Name Resolution

0 declarations

getAddress

valuegetAddress :: Family f => Socket f t p -> IO (SocketAddress f)
#

Get a socket's (local) address.

> (socket :: IO (Socket Inet Stream TCP)) >>= getAddress
SocketAddressInet {inetAddress = InetAddress 0.0.0.0, inetPort = InetPort 0}

getAddressInfo

classclass Family f => HasAddressInfo f where
#

This class is for address families that support name resolution.

Methods

  • getAddressInfo :: (Type t, Protocol p) => Maybe ByteString -> Maybe ByteString -> AddressInfoFlags -> IO [AddressInfo f t p]

    Maps names to addresses (i.e. by DNS lookup).

    The operation throws AddressInfoExceptions.

    Contrary to the underlying getaddrinfo operation this wrapper is typesafe and thus only returns records that match the address, type and protocol encoded in the type. This is the price we have to pay for typesafe sockets and extensibility.

    If you need different types of records, you need to start several queries. If you want to connect to both IPv4 and IPV6 addresses use aiV4Mapped and use IPv6-sockets.

    getAddressInfo (Just "www.haskell.org") (Just "https") mempty :: IO [AddressInfo Inet Stream TCP]
    > [AddressInfo {addressInfoFlags = AddressInfoFlags 0, socketAddress = SocketAddressInet {inetAddress = InetAddress 162.242.239.16, inetPort = InetPort 443}, canonicalName = Nothing}]
    > getAddressInfo (Just "www.haskell.org") (Just "80") aiV4Mapped :: IO [AddressInfo Inet6 Stream TCP]
    [AddressInfo {
       addressInfoFlags = AddressInfoFlags 8,
       socketAddress    = SocketAddressInet6 {inet6Address = Inet6Address 2400:cb00:2048:0001:0000:0000:6ca2:cc3c, inet6Port = Inet6Port 80, inet6FlowInfo = Inet6FlowInfo 0, inet6ScopeId = Inet6ScopeId 0},
       canonicalName    = Nothing }]
    > getAddressInfo (Just "darcs.haskell.org") Nothing aiV4Mapped :: IO [AddressInfo Inet6 Stream TCP]
    [AddressInfo {
       addressInfoFlags = AddressInfoFlags 8,
       socketAddress    = SocketAddressInet6 {inet6Address = Inet6Address 0000:0000:0000:0000:0000:ffff:17fd:e1ad, inet6Port = Inet6Port 0, inet6FlowInfo = Inet6FlowInfo 0, inet6ScopeId = Inet6ScopeId 0},
       canonicalName    = Nothing }]
    > getAddressInfo (Just "darcs.haskell.org") Nothing mempty :: IO [AddressInfo Inet6 Stream TCP]
    *** Exception: AddressInfoException "Name or service not known"
Instances2HasAddressInfo

getNameInfo

classclass Family f => HasNameInfo f where
#

This class is for address families that support reverse name resolution.

Methods

Instances2HasNameInfo
  • HasNameInfo InetDefined in socket-0.8.3.0 · System.Socket.Internal.AddressInfo
  • HasNameInfo Inet6Defined in socket-0.8.3.0 · System.Socket.Internal.AddressInfo

Options

1 declaration
classclass SocketOption o where
#

SocketOptions allow to read and write certain properties of a socket.

Methods

Instances5SocketOption

Error

datadata Error
#

Reports the last error that occured on the socket.

  • Also known as SO_ERROR.

  • The operation setSocketOption always throws eInvalid for this option.

  • Use with care in the presence of concurrency!

Instances4Eq, Ord, Show, SocketOption
  • Eq ErrorDefined in socket-0.8.3.0 · System.Socket.Internal.SocketOption
  • Ord ErrorDefined in socket-0.8.3.0 · System.Socket.Internal.SocketOption
  • Show ErrorDefined in socket-0.8.3.0 · System.Socket.Internal.SocketOption
  • SocketOption ErrorDefined in socket-0.8.3.0 · System.Socket.Internal.SocketOption

ReuseAddress

datadata ReuseAddress
#

Allows or disallows the reuse of a local address in a bind call.

  • Also known as SO_REUSEADDR.

  • This is particularly useful when experiencing eAddressInUse exceptions.

Constructors

Instances4Eq, Ord, Show, SocketOption

KeepAlive

datadata KeepAlive
#

When enabled the protocol checks in a protocol-specific manner if the other end is still alive.

  • Also known as SO_KEEPALIVE.

Constructors

Instances4Eq, Ord, Show, SocketOption
  • Eq KeepAliveDefined in socket-0.8.3.0 · System.Socket.Internal.SocketOption
  • Ord KeepAliveDefined in socket-0.8.3.0 · System.Socket.Internal.SocketOption
  • Show KeepAliveDefined in socket-0.8.3.0 · System.Socket.Internal.SocketOption
  • SocketOption KeepAliveDefined in socket-0.8.3.0 · System.Socket.Internal.SocketOption

Flags

0 declarations

MessageFlags

newtypenewtype MessageFlags
#

Use the Monoid instance to combine several flags:

mconcat [msgNoSignal, msgWaitAll]

Use the Bits instance to check whether a flag is set:

if flags .&. msgEndOfRecord /= mempty then ...

Constructors

Instances6Eq, Show, Semigroup, Monoid, Bits, Storable
MSG_NOSIGNAL

Suppresses the generation of PIPE signals when writing to a socket that is no longer connected.

Although this flag is POSIX, it is not available on all platforms. Try

msgNoSignal /= mempty

in order to check whether this flag is defined on a certain platform. It is safe to just use this constant even if it might not have effect on a certain target platform. The platform independence of this flag is therefore fulfilled to some extent.

Some more explanation on the platform specific behaviour:

  • Linux defines and supports MSG_NOSIGNAL and properly suppresses the generation of broken pipe-related signals.

  • Windows does not define it, but does not generate signals either.

  • OSX does not define it, but generates PIPE signals. The GHC runtime ignores them if you don't hook them explicitly. The non-portable socket option SO_NOSIGPIPE may be used disable signals on a per-socket basis.

It is safe and advised to always use this flag unless one wants to explictly hook and handle the PIPE signal which is not very useful in todays multi-threaded environments anyway. Although GHC's RTS ignores the signal by default it causes an unnecessary interruption.

Untested: Use at your own risk!

MSG_OOB

Used to send and receive out-of-band data. Consult the relevant standards for details.

Untested: Use at your own risk!

MSG_WAITALL

A receive call shall not return unless the requested number of bytes becomes available.

AddressInfoFlags

newtypenewtype AddressInfoFlags
#

Use the Monoid instance to combine several flags:

mconcat [aiAddressConfig, aiV4Mapped]
Instances5Eq, Show, Semigroup, Monoid, Bits

AI_ALL: Return both IPv4 (as v4-mapped IPv6 address) and IPv6 addresses when aiV4Mapped is set independent of whether IPv6 addresses exist for this name.

NameInfoFlags

newtypenewtype NameInfoFlags
#

Use the Monoid instance to combine several flags:

mconcat [niNameRequired, niNoFullyQualifiedDomainName]
Instances5Eq, Show, Semigroup, Monoid, Bits

Exceptions

0 declarations

SocketException

Operation already in progress.

NOTE: This exception shall not be thrown by any public operation in this library, but is handled internally.

Interrupted system call.

NOTE: This exception shall not be thrown by any public operation in this library, but is handled internally.

Resource temporarily unavailable.

NOTE: This exception shall not be thrown by any public operation in this library, but is handled internally.

newtypenewtype SocketException
#

Contains the error code that can be matched against.

Hint: Use guards or MultiWayIf to match against specific exceptions:

if | e == eAddressInUse -> ...
   | e == eAddressNotAvailable -> ...
   | otherwise -> ...

Constructors

Instances4Eq, Ord, Show, Exception

AddressInfoException

newtypenewtype AddressInfoException
#

Contains the error code that can be matched against.

Hint: Use guards or MultiWayIf to match against specific exceptions:

if | e == eaiFail -> ...
   | e == eaiNoName -> ...
   | otherwise -> ...
Instances3Eq, Show, Exception