PageRenderTime 39ms CodeModel.GetById 2ms app.highlight 29ms RepoModel.GetById 1ms app.codeStats 0ms

/src/System/ZMQ4.hs

http://github.com/twittner/zeromq-haskell
Haskell | 1007 lines | 591 code | 170 blank | 246 comment | 6 complexity | 5918bd0b9e1373081c0ed003aa2e2c39 MD5 | raw file
   1{-# LANGUAGE CPP                #-}
   2{-# LANGUAGE GADTs              #-}
   3{-# LANGUAGE DeriveDataTypeable #-}
   4{-# LANGUAGE DeriveGeneric      #-}
   5
   6-- |
   7-- Module      : System.ZMQ4
   8-- Copyright   : (c) 2010-2013 Toralf Wittner
   9-- License     : MIT
  10-- Maintainer  : Toralf Wittner <tw@dtex.org>
  11-- Stability   : experimental
  12-- Portability : non-portable
  13--
  14-- 0MQ haskell binding. The API closely follows the C-API of 0MQ with
  15-- the main difference being that sockets are typed.
  16--
  17-- /Notes/
  18--
  19-- Many option settings use a 'Restriction' to further constrain the
  20-- range of possible values of their integral types. For example
  21-- the maximum message size can be given as -1, which means no limit
  22-- or by greater values, which denote the message size in bytes. The
  23-- type of 'setMaxMessageSize' is therefore:
  24--
  25-- @setMaxMessageSize :: Integral i
  26--                    => Restricted (Nneg1, Int64) i
  27--                    -> Socket a
  28--                    -> IO ()@
  29--
  30-- which means any integral value in the range of @-1@ to
  31-- (@maxBound :: Int64@) can be given. To create a restricted
  32-- value from plain value, use 'toRestricted' or 'restrict'.
  33
  34module System.ZMQ4
  35  ( -- * Type Definitions
  36    -- ** Socket Types
  37    Pair   (..)
  38  , Pub    (..)
  39  , Sub    (..)
  40  , XPub   (..)
  41  , XSub   (..)
  42  , Req    (..)
  43  , Rep    (..)
  44  , Dealer (..)
  45  , Router (..)
  46  , XReq
  47  , XRep
  48  , Pull   (..)
  49  , Push   (..)
  50  , Stream (..)
  51
  52    -- ** Socket type-classes
  53  , SocketType
  54  , Sender
  55  , Receiver
  56  , Subscriber
  57  , SocketLike
  58  , Conflatable
  59  , SendProbe
  60
  61    -- ** Various type definitions
  62  , Size
  63  , Context
  64  , Socket
  65  , Flag              (..)
  66  , Switch            (..)
  67  , Timeout
  68  , Event             (..)
  69  , EventType         (..)
  70  , EventMsg          (..)
  71  , Poll              (..)
  72  , KeyFormat         (..)
  73  , SecurityMechanism (..)
  74
  75    -- * General Operations
  76  , withContext
  77  , withSocket
  78  , bind
  79  , unbind
  80  , connect
  81  , disconnect
  82  , send
  83  , send'
  84  , sendMulti
  85  , receive
  86  , receiveMulti
  87  , version
  88  , monitor
  89  , socketMonitor
  90  , poll
  91
  92  , System.ZMQ4.subscribe
  93  , System.ZMQ4.unsubscribe
  94
  95    -- * Context Options (Read)
  96  , ioThreads
  97  , maxSockets
  98
  99    -- * Context Options (Write)
 100  , setIoThreads
 101  , setMaxSockets
 102
 103    -- * Socket Options (Read)
 104  , System.ZMQ4.affinity
 105  , System.ZMQ4.backlog
 106  , System.ZMQ4.conflate
 107  , System.ZMQ4.curvePublicKey
 108  , System.ZMQ4.curveSecretKey
 109  , System.ZMQ4.curveServerKey
 110  , System.ZMQ4.delayAttachOnConnect
 111  , System.ZMQ4.events
 112  , System.ZMQ4.fileDescriptor
 113  , System.ZMQ4.identity
 114  , System.ZMQ4.immediate
 115  , System.ZMQ4.ipv4Only
 116  , System.ZMQ4.ipv6
 117  , System.ZMQ4.lastEndpoint
 118  , System.ZMQ4.linger
 119  , System.ZMQ4.maxMessageSize
 120  , System.ZMQ4.mcastHops
 121  , System.ZMQ4.mechanism
 122  , System.ZMQ4.moreToReceive
 123  , System.ZMQ4.plainServer
 124  , System.ZMQ4.plainPassword
 125  , System.ZMQ4.plainUserName
 126  , System.ZMQ4.rate
 127  , System.ZMQ4.receiveBuffer
 128  , System.ZMQ4.receiveHighWM
 129  , System.ZMQ4.receiveTimeout
 130  , System.ZMQ4.reconnectInterval
 131  , System.ZMQ4.reconnectIntervalMax
 132  , System.ZMQ4.recoveryInterval
 133  , System.ZMQ4.sendBuffer
 134  , System.ZMQ4.sendHighWM
 135  , System.ZMQ4.sendTimeout
 136  , System.ZMQ4.tcpKeepAlive
 137  , System.ZMQ4.tcpKeepAliveCount
 138  , System.ZMQ4.tcpKeepAliveIdle
 139  , System.ZMQ4.tcpKeepAliveInterval
 140  , System.ZMQ4.zapDomain
 141
 142    -- * Socket Options (Write)
 143  , setAffinity
 144  , setBacklog
 145  , setConflate
 146  , setCurveServer
 147  , setCurvePublicKey
 148  , setCurveSecretKey
 149  , setCurveServerKey
 150  , setDelayAttachOnConnect
 151  , setIdentity
 152  , setImmediate
 153  , setIpv4Only
 154  , setIpv6
 155  , setLinger
 156  , setMaxMessageSize
 157  , setMcastHops
 158  , setPlainServer
 159  , setPlainPassword
 160  , setPlainUserName
 161  , setProbeRouter
 162  , setRate
 163  , setReceiveBuffer
 164  , setReceiveHighWM
 165  , setReceiveTimeout
 166  , setReconnectInterval
 167  , setReconnectIntervalMax
 168  , setRecoveryInterval
 169  , setReqCorrelate
 170  , setReqRelaxed
 171  , setRouterMandatory
 172  , setSendBuffer
 173  , setSendHighWM
 174  , setSendTimeout
 175  , setTcpAcceptFilter
 176  , setTcpKeepAlive
 177  , setTcpKeepAliveCount
 178  , setTcpKeepAliveIdle
 179  , setTcpKeepAliveInterval
 180  , setXPubVerbose
 181
 182    -- * Restrictions
 183  , Data.Restricted.restrict
 184  , Data.Restricted.toRestricted
 185
 186    -- * Error Handling
 187  , ZMQError
 188  , errno
 189  , source
 190  , message
 191
 192    -- * Low-level Functions
 193  , init
 194  , term
 195  , shutdown
 196  , context
 197  , socket
 198  , close
 199  , waitRead
 200  , waitWrite
 201  , z85Encode
 202  , z85Decode
 203
 204    -- * Utils
 205  , proxy
 206  , curveKeyPair
 207  ) where
 208
 209import Control.Applicative
 210import Control.Exception
 211import Control.Monad (unless)
 212import Control.Monad.IO.Class
 213import Data.List (intersect, foldl')
 214import Data.List.NonEmpty (NonEmpty)
 215import Data.Restricted
 216import Data.Traversable (forM)
 217import Data.Typeable
 218import Foreign hiding (throwIf, throwIf_, throwIfNull, void)
 219import Foreign.C.String
 220import Foreign.C.Types (CInt, CShort)
 221import System.Posix.Types (Fd(..))
 222import System.ZMQ4.Internal
 223import System.ZMQ4.Internal.Base
 224import System.ZMQ4.Internal.Error
 225import Prelude hiding (init)
 226
 227import qualified Data.ByteString           as SB
 228import qualified Data.ByteString.Lazy      as LB
 229import qualified Data.List.NonEmpty        as S
 230import qualified Prelude                   as P
 231import qualified System.ZMQ4.Internal.Base as B
 232
 233import GHC.Conc (threadWaitRead)
 234import GHC.Generics(Generic)
 235
 236-----------------------------------------------------------------------------
 237-- Socket Types
 238
 239-- | <http://api.zeromq.org/4-0:zmq-socket ZMQ_PAIR>
 240data Pair = Pair deriving (Eq, Typeable, Generic)
 241
 242-- | <http://api.zeromq.org/4-0:zmq-socket ZMQ_PUB>
 243data Pub = Pub deriving (Eq, Typeable, Generic)
 244
 245-- | <http://api.zeromq.org/4-0:zmq-socket ZMQ_SUB>
 246data Sub = Sub deriving (Eq, Typeable, Generic)
 247
 248-- | <http://api.zeromq.org/4-0:zmq-socket ZMQ_XPUB>
 249data XPub = XPub deriving (Eq, Typeable, Generic)
 250
 251-- | <http://api.zeromq.org/4-0:zmq-socket ZMQ_XSUB>
 252data XSub = XSub deriving (Eq, Typeable, Generic)
 253
 254-- | <http://api.zeromq.org/4-0:zmq-socket ZMQ_REQ>
 255data Req = Req deriving (Eq, Typeable, Generic)
 256
 257-- | <http://api.zeromq.org/4-0:zmq-socket ZMQ_REP>
 258data Rep = Rep deriving (Eq, Typeable, Generic)
 259
 260-- | <http://api.zeromq.org/4-0:zmq-socket ZMQ_DEALER>
 261data Dealer = Dealer deriving (Eq, Typeable, Generic)
 262
 263-- | <http://api.zeromq.org/4-0:zmq-socket ZMQ_ROUTER>
 264data Router = Router deriving (Eq, Typeable, Generic)
 265
 266-- | <http://api.zeromq.org/4-0:zmq-socket ZMQ_PULL>
 267data Pull = Pull deriving (Eq, Typeable, Generic)
 268
 269-- | <http://api.zeromq.org/4-0:zmq-socket ZMQ_PUSH>
 270data Push = Push deriving (Eq, Typeable, Generic)
 271
 272-- | <http://api.zeromq.org/4-0:zmq-socket ZMQ_STREAM>
 273data Stream = Stream deriving (Eq, Typeable, Generic)
 274
 275type XReq = Dealer
 276{-# DEPRECATED XReq "Use Dealer" #-}
 277
 278type XRep = Router
 279{-# DEPRECATED XRep "Use Router" #-}
 280
 281-----------------------------------------------------------------------------
 282-- Socket Type Classifications
 283
 284-- | Sockets which can 'subscribe'.
 285class Subscriber a
 286
 287-- | Sockets which can 'send'.
 288class Sender a
 289
 290-- | Sockets which can 'receive'.
 291class Receiver a
 292
 293-- | Sockets which can be 'conflate'd.
 294class Conflatable a
 295
 296-- | Sockets which can send probes (cf. 'setProbeRouter').
 297class SendProbe a
 298
 299instance SocketType Pair where zmqSocketType = const pair
 300instance Sender     Pair
 301instance Receiver   Pair
 302
 303instance SocketType  Pub where zmqSocketType = const pub
 304instance Sender      Pub
 305instance Conflatable Pub
 306
 307instance SocketType  Sub where zmqSocketType = const sub
 308instance Subscriber  Sub
 309instance Receiver    Sub
 310instance Conflatable Sub
 311
 312instance SocketType XPub where zmqSocketType = const xpub
 313instance Sender     XPub
 314instance Receiver   XPub
 315
 316instance SocketType XSub where zmqSocketType = const xsub
 317instance Sender     XSub
 318instance Receiver   XSub
 319
 320instance SocketType Req where zmqSocketType = const request
 321instance Sender     Req
 322instance Receiver   Req
 323instance SendProbe  Req
 324
 325instance SocketType Rep where zmqSocketType = const response
 326instance Sender     Rep
 327instance Receiver   Rep
 328
 329instance SocketType  Dealer where zmqSocketType = const dealer
 330instance Sender      Dealer
 331instance Receiver    Dealer
 332instance Conflatable Dealer
 333instance SendProbe   Dealer
 334
 335instance SocketType Router where zmqSocketType = const router
 336instance Sender     Router
 337instance Receiver   Router
 338instance SendProbe  Router
 339
 340instance SocketType  Pull where zmqSocketType = const pull
 341instance Receiver    Pull
 342instance Conflatable Pull
 343
 344instance SocketType  Push where zmqSocketType = const push
 345instance Sender      Push
 346instance Conflatable Push
 347
 348instance SocketType Stream where zmqSocketType = const stream
 349instance Sender     Stream
 350instance Receiver   Stream
 351
 352-----------------------------------------------------------------------------
 353
 354-- | Socket events.
 355data Event =
 356    In     -- ^ @ZMQ_POLLIN@ (incoming messages)
 357  | Out    -- ^ @ZMQ_POLLOUT@ (outgoing messages, i.e. at least 1 byte can be written)
 358  | Err    -- ^ @ZMQ_POLLERR@
 359  deriving (Eq, Ord, Read, Show)
 360
 361-- | A 'Poll' value contains the object to poll (a 0MQ socket or a file
 362-- descriptor), the set of 'Event's which are of interest and--optionally--
 363-- a callback-function which is invoked iff the set of interested events
 364-- overlaps with the actual events.
 365data Poll s m where
 366    Sock :: s t -> [Event] -> Maybe ([Event] -> m ()) -> Poll s m
 367    File :: Fd -> [Event] -> Maybe ([Event] -> m ()) -> Poll s m
 368
 369-- | Return the runtime version of the underlying 0MQ library as a
 370-- (major, minor, patch) triple.
 371version :: IO (Int, Int, Int)
 372version =
 373    with 0 $ \major_ptr ->
 374    with 0 $ \minor_ptr ->
 375    with 0 $ \patch_ptr ->
 376        c_zmq_version major_ptr minor_ptr patch_ptr >>
 377        tupleUp <$> peek major_ptr <*> peek minor_ptr <*> peek patch_ptr
 378  where
 379    tupleUp a b c = (fromIntegral a, fromIntegral b, fromIntegral c)
 380
 381init :: Size -> IO Context
 382init n = do
 383    c <- context
 384    setIoThreads n c
 385    return c
 386{-# DEPRECATED init "Use context" #-}
 387
 388-- | Initialize a 0MQ context.
 389-- Equivalent to <http://api.zeromq.org/4-0:zmq-ctx-new zmq_ctx_new>.
 390context :: IO Context
 391context = Context <$> throwIfNull "init" c_zmq_ctx_new
 392
 393-- | Terminate a 0MQ context.
 394-- Equivalent to <http://api.zeromq.org/4-0:zmq-ctx-term zmq_ctx_term>.
 395term :: Context -> IO ()
 396term c = throwIfMinus1Retry_ "term" . c_zmq_ctx_term . _ctx $ c
 397
 398-- | Shutdown a 0MQ context.
 399-- Equivalent to <http://api.zeromq.org/4-0:zmq-ctx-shutdown zmq_ctx_shutdown>.
 400shutdown :: Context -> IO ()
 401shutdown = throwIfMinus1_ "shutdown" . c_zmq_ctx_shutdown . _ctx
 402
 403-- | Run an action with a 0MQ context.  The 'Context' supplied to your
 404-- action will /not/ be valid after the action either returns or
 405-- throws an exception.
 406withContext :: (Context -> IO a) -> IO a
 407withContext act =
 408  bracket (throwIfNull "withContext (new)" $ c_zmq_ctx_new)
 409          (throwIfMinus1Retry_ "withContext (term)" . c_zmq_ctx_term)
 410          (act . Context)
 411
 412-- | Run an action with a 0MQ socket. The socket will be closed after running
 413-- the supplied action even if an error occurs. The socket supplied to your
 414-- action will /not/ be valid after the action terminates.
 415withSocket :: SocketType a => Context -> a -> (Socket a -> IO b) -> IO b
 416withSocket c t = bracket (socket c t) close
 417
 418-- | Create a new 0MQ socket within the given context. 'withSocket' provides
 419-- automatic socket closing and may be safer to use.
 420socket :: SocketType a => Context -> a -> IO (Socket a)
 421socket c t = Socket <$> mkSocketRepr t c
 422
 423-- | Close a 0MQ socket. 'withSocket' provides automatic socket closing and may
 424-- be safer to use.
 425close :: Socket a -> IO ()
 426close = closeSock . _socketRepr
 427
 428-- | Subscribe Socket to given subscription.
 429subscribe :: Subscriber a => Socket a -> SB.ByteString -> IO ()
 430subscribe s = setByteStringOpt s B.subscribe
 431
 432-- | Unsubscribe Socket from given subscription.
 433unsubscribe :: Subscriber a => Socket a -> SB.ByteString -> IO ()
 434unsubscribe s = setByteStringOpt s B.unsubscribe
 435
 436-- Read Only
 437
 438-- | <http://api.zeromq.org/4-0:zmq-getsockopt zmq_getsockopt ZMQ_EVENTS>.
 439events :: Socket a -> IO [Event]
 440events s = toEvents <$> getIntOpt s B.events 0
 441
 442-- | <http://api.zeromq.org/4-0:zmq-getsockopt zmq_getsockopt ZMQ_FD>.
 443fileDescriptor :: Socket a -> IO Fd
 444fileDescriptor s = Fd . fromIntegral <$> getInt32Option B.filedesc s
 445
 446-- | <http://api.zeromq.org/4-0:zmq-getsockopt zmq_getsockopt ZMQ_RCVMORE>.
 447moreToReceive :: Socket a -> IO Bool
 448moreToReceive s = (== 1) <$> getInt32Option B.receiveMore s
 449
 450-- Read
 451
 452-- | <http://api.zeromq.org/4-0:zmq-ctx-get zmq_ctx_get ZMQ_IO_THREADS>.
 453ioThreads :: Context -> IO Word
 454ioThreads = ctxIntOption "ioThreads" _ioThreads
 455
 456-- | <http://api.zeromq.org/4-0:zmq-ctx-get zmq_ctx_get ZMQ_MAX_SOCKETS>.
 457maxSockets :: Context -> IO Word
 458maxSockets = ctxIntOption "maxSockets" _maxSockets
 459
 460-- | Restricts the outgoing and incoming socket buffers to a single message.
 461conflate :: Conflatable a => Socket a -> IO Bool
 462conflate s = (== 1) <$> getInt32Option B.conflate s
 463
 464-- | <http://api.zeromq.org/4-0:zmq-getsockopt zmq_getsockopt ZMQ_IMMEDIATE>.
 465immediate :: Socket a -> IO Bool
 466immediate s = (== 1) <$> getInt32Option B.immediate s
 467
 468-- | <http://api.zeromq.org/4-0:zmq-getsockopt zmq_getsockopt ZMQ_IDENTITY>.
 469identity :: Socket a -> IO SB.ByteString
 470identity s = getByteStringOpt s B.identity
 471
 472-- | <http://api.zeromq.org/4-0:zmq-getsockopt zmq_getsockopt ZMQ_AFFINITY>.
 473affinity :: Socket a -> IO Word64
 474affinity s = getIntOpt s B.affinity 0
 475
 476-- | <http://api.zeromq.org/4-0:zmq-getsockopt zmq_getsockopt ZMQ_MAXMSGSIZE>.
 477maxMessageSize :: Socket a -> IO Int64
 478maxMessageSize s = getIntOpt s B.maxMessageSize 0
 479
 480ipv4Only :: Socket a -> IO Bool
 481ipv4Only s = (== 1) <$> getInt32Option B.ipv4Only s
 482{-# DEPRECATED ipv4Only "Use ipv6" #-}
 483
 484-- | <http://api.zeromq.org/4-0:zmq-getsockopt zmq_getsockopt ZMQ_IPV6>.
 485ipv6 :: Socket a -> IO Bool
 486ipv6 s = (== 1) <$> getInt32Option B.ipv6 s
 487
 488-- | <http://api.zeromq.org/4-0:zmq-getsockopt zmq_getsockopt ZMQ_BACKLOG>.
 489backlog :: Socket a -> IO Int
 490backlog = getInt32Option B.backlog
 491
 492delayAttachOnConnect :: Socket a -> IO Bool
 493delayAttachOnConnect s = (== 1) <$> getInt32Option B.delayAttachOnConnect s
 494{-# DEPRECATED delayAttachOnConnect "Use immediate" #-}
 495
 496-- | <http://api.zeromq.org/4-0:zmq-getsockopt zmq_getsockopt ZMQ_LINGER>.
 497linger :: Socket a -> IO Int
 498linger = getInt32Option B.linger
 499
 500-- | <http://api.zeromq.org/4-0:zmq-getsockopt zmq_getsockopt ZMQ_LAST_ENDPOINT>.
 501lastEndpoint :: Socket a -> IO String
 502lastEndpoint s = getStrOpt s B.lastEndpoint
 503
 504-- | <http://api.zeromq.org/4-0:zmq-getsockopt zmq_getsockopt ZMQ_RATE>.
 505rate :: Socket a -> IO Int
 506rate = getInt32Option B.rate
 507
 508-- | <http://api.zeromq.org/4-0:zmq-getsockopt zmq_getsockopt ZMQ_RCVBUF>.
 509receiveBuffer :: Socket a -> IO Int
 510receiveBuffer = getInt32Option B.receiveBuf
 511
 512-- | <http://api.zeromq.org/4-0:zmq-getsockopt zmq_getsockopt ZMQ_RECONNECT_IVL>.
 513reconnectInterval :: Socket a -> IO Int
 514reconnectInterval = getInt32Option B.reconnectIVL
 515
 516-- | <http://api.zeromq.org/4-0:zmq-getsockopt zmq_getsockopt ZMQ_RECONNECT_IVL_MAX>.
 517reconnectIntervalMax :: Socket a -> IO Int
 518reconnectIntervalMax = getInt32Option B.reconnectIVLMax
 519
 520-- | <http://api.zeromq.org/4-0:zmq-getsockopt zmq_getsockopt ZMQ_RECOVERY_IVL>.
 521recoveryInterval :: Socket a -> IO Int
 522recoveryInterval = getInt32Option B.recoveryIVL
 523
 524-- | <http://api.zeromq.org/4-0:zmq-getsockopt zmq_getsockopt ZMQ_SNDBUF>.
 525sendBuffer :: Socket a -> IO Int
 526sendBuffer = getInt32Option B.sendBuf
 527
 528-- | <http://api.zeromq.org/4-0:zmq-getsockopt zmq_getsockopt ZMQ_MULTICAST_HOPS>.
 529mcastHops :: Socket a -> IO Int
 530mcastHops = getInt32Option B.mcastHops
 531
 532-- | <http://api.zeromq.org/4-0:zmq-getsockopt zmq_getsockopt ZMQ_RCVHWM>.
 533receiveHighWM :: Socket a -> IO Int
 534receiveHighWM = getInt32Option B.receiveHighWM
 535
 536-- | <http://api.zeromq.org/4-0:zmq-getsockopt zmq_getsockopt ZMQ_RCVTIMEO>.
 537receiveTimeout :: Socket a -> IO Int
 538receiveTimeout = getInt32Option B.receiveTimeout
 539
 540-- | <http://api.zeromq.org/4-0:zmq-getsockopt zmq_getsockopt ZMQ_SNDTIMEO>.
 541sendTimeout :: Socket a -> IO Int
 542sendTimeout = getInt32Option B.sendTimeout
 543
 544-- | <http://api.zeromq.org/4-0:zmq-getsockopt zmq_getsockopt ZMQ_SNDHWM>.
 545sendHighWM :: Socket a -> IO Int
 546sendHighWM = getInt32Option B.sendHighWM
 547
 548-- | <http://api.zeromq.org/4-0:zmq-getsockopt zmq_getsockopt ZMQ_TCP_KEEPALIVE>.
 549tcpKeepAlive :: Socket a -> IO Switch
 550tcpKeepAlive = fmap (toSwitch "Invalid ZMQ_TCP_KEEPALIVE")
 551             . getInt32Option B.tcpKeepAlive
 552
 553-- | <http://api.zeromq.org/4-0:zmq-getsockopt zmq_getsockopt ZMQ_TCP_KEEPALIVE_CNT>.
 554tcpKeepAliveCount :: Socket a -> IO Int
 555tcpKeepAliveCount = getInt32Option B.tcpKeepAliveCount
 556
 557-- | <http://api.zeromq.org/4-0:zmq-getsockopt zmq_getsockopt ZMQ_TCP_KEEPALIVE_IDLE>.
 558tcpKeepAliveIdle :: Socket a -> IO Int
 559tcpKeepAliveIdle = getInt32Option B.tcpKeepAliveIdle
 560
 561-- | <http://api.zeromq.org/4-0:zmq-getsockopt zmq_getsockopt ZMQ_TCP_KEEPALIVE_INTVL>.
 562tcpKeepAliveInterval :: Socket a -> IO Int
 563tcpKeepAliveInterval = getInt32Option B.tcpKeepAliveInterval
 564
 565-- | <http://api.zeromq.org/4-0:zmq-getsockopt zmq_getsockopt ZMQ_MECHANISM>.
 566mechanism :: Socket a -> IO SecurityMechanism
 567mechanism = fmap (fromMechanism "Invalid ZMQ_MECHANISM")
 568          . getInt32Option B.mechanism
 569
 570-- | <http://api.zeromq.org/4-0:zmq-getsockopt zmq_getsockopt ZMQ_PLAIN_SERVER>.
 571plainServer :: Socket a -> IO Bool
 572plainServer = fmap (== 1) . getInt32Option B.plainServer
 573
 574-- | <http://api.zeromq.org/4-0:zmq-getsockopt zmq_getsockopt ZMQ_PLAIN_USERNAME>.
 575plainUserName :: Socket a -> IO SB.ByteString
 576plainUserName s = getByteStringOpt s B.plainUserName
 577
 578-- | <http://api.zeromq.org/4-0:zmq-getsockopt zmq_getsockopt ZMQ_PLAIN_PASSWORD>.
 579plainPassword :: Socket a -> IO SB.ByteString
 580plainPassword s = getByteStringOpt s B.plainPassword
 581
 582-- | <http://api.zeromq.org/4-0:zmq-getsockopt zmq_getsockopt ZMQ_ZAP_DOMAIN>.
 583zapDomain :: Socket a -> IO SB.ByteString
 584zapDomain s = getByteStringOpt s B.zapDomain
 585
 586-- | <http://api.zeromq.org/4-0:zmq-getsockopt zmq_getsockopt ZMQ_CURVE_PUBLICKEY>.
 587curvePublicKey :: KeyFormat f -> Socket a -> IO SB.ByteString
 588curvePublicKey f s = getKey f s B.curvePublicKey
 589
 590-- | <http://api.zeromq.org/4-0:zmq-getsockopt zmq_getsockopt ZMQ_CURVE_SERVERKEY>.
 591curveServerKey :: KeyFormat f -> Socket a -> IO SB.ByteString
 592curveServerKey f s = getKey f s B.curveServerKey
 593
 594-- | <http://api.zeromq.org/4-0:zmq-getsockopt zmq_getsockopt ZMQ_CURVE_SECRETKEY>.
 595curveSecretKey :: KeyFormat f -> Socket a -> IO SB.ByteString
 596curveSecretKey f s = getKey f s B.curveSecretKey
 597
 598-- Write
 599
 600-- | <http://api.zeromq.org/4-0:zmq-ctx-set zmq_ctx_get ZMQ_IO_THREADS>.
 601setIoThreads :: Word -> Context -> IO ()
 602setIoThreads n = setCtxIntOption "ioThreads" _ioThreads n
 603
 604-- | <http://api.zeromq.org/4-0:zmq-ctx-set zmq_ctx_get ZMQ_MAX_SOCKETS>.
 605setMaxSockets :: Word -> Context -> IO ()
 606setMaxSockets n = setCtxIntOption "maxSockets" _maxSockets n
 607
 608-- | Restrict the outgoing and incoming socket buffers to a single message.
 609setConflate :: Conflatable a => Bool -> Socket a -> IO ()
 610setConflate x s = setIntOpt s B.conflate (bool2cint x)
 611
 612-- | <http://api.zeromq.org/4-0:zmq-setsockopt zmq_setsockopt ZMQ_IMMEDIATE>.
 613setImmediate :: Bool -> Socket a -> IO ()
 614setImmediate x s = setIntOpt s B.immediate (bool2cint x)
 615
 616-- | <http://api.zeromq.org/4-0:zmq-setsockopt zmq_setsockopt ZMQ_IDENTITY>.
 617setIdentity :: Restricted (N1, N254) SB.ByteString -> Socket a -> IO ()
 618setIdentity x s = setByteStringOpt s B.identity (rvalue x)
 619
 620-- | <http://api.zeromq.org/4-0:zmq-setsockopt zmq_setsockopt ZMQ_AFFINITY>.
 621setAffinity :: Word64 -> Socket a -> IO ()
 622setAffinity x s = setIntOpt s B.affinity x
 623
 624setDelayAttachOnConnect :: Bool -> Socket a -> IO ()
 625setDelayAttachOnConnect x s = setIntOpt s B.delayAttachOnConnect (bool2cint x)
 626{-# DEPRECATED setDelayAttachOnConnect "Use setImmediate" #-}
 627
 628-- | <http://api.zeromq.org/4-0:zmq-setsockopt zmq_setsockopt ZMQ_MAXMSGSIZE>.
 629setMaxMessageSize :: Integral i => Restricted (Nneg1, Int64) i -> Socket a -> IO ()
 630setMaxMessageSize x s = setIntOpt s B.maxMessageSize ((fromIntegral . rvalue $ x) :: Int64)
 631
 632setIpv4Only :: Bool -> Socket a -> IO ()
 633setIpv4Only x s = setIntOpt s B.ipv4Only (bool2cint x)
 634{-# DEPRECATED setIpv4Only "Use setIpv6" #-}
 635
 636-- | <http://api.zeromq.org/4-0:zmq-setsockopt zmq_setsockopt ZMQ_IPV6>.
 637setIpv6 :: Bool -> Socket a -> IO ()
 638setIpv6 x s = setIntOpt s B.ipv6 (bool2cint x)
 639
 640-- | <http://api.zeromq.org/4-0:zmq-setsockopt zmq_setsockopt ZMQ_PLAIN_SERVER>.
 641setPlainServer :: Bool -> Socket a -> IO ()
 642setPlainServer x s = setIntOpt s B.plainServer (bool2cint x)
 643
 644-- | <http://api.zeromq.org/4-0:zmq-setsockopt zmq_setsockopt ZMQ_CURVE_SERVER>.
 645setCurveServer :: Bool -> Socket a -> IO ()
 646setCurveServer x s = setIntOpt s B.curveServer (bool2cint x)
 647
 648-- | <http://api.zeromq.org/4-0:zmq-setsockopt zmq_setsockopt ZMQ_PLAIN_USERNAME>.
 649setPlainUserName :: Restricted (N1, N254) SB.ByteString -> Socket a -> IO ()
 650setPlainUserName x s = setByteStringOpt s B.plainUserName (rvalue x)
 651
 652-- | <http://api.zeromq.org/4-0:zmq-setsockopt zmq_setsockopt ZMQ_PLAIN_USERNAME>.
 653setPlainPassword :: Restricted (N1, N254) SB.ByteString -> Socket a -> IO ()
 654setPlainPassword x s = setByteStringOpt s B.plainPassword (rvalue x)
 655
 656-- | <http://api.zeromq.org/4-0:zmq-setsockopt zmq_setsockopt ZMQ_LINGER>.
 657setLinger :: Integral i => Restricted (Nneg1, Int32) i -> Socket a -> IO ()
 658setLinger = setInt32OptFromRestricted B.linger
 659
 660-- | <http://api.zeromq.org/4-0:zmq-setsockopt zmq_setsockopt ZMQ_RCVTIMEO>.
 661setReceiveTimeout :: Integral i => Restricted (Nneg1, Int32) i -> Socket a -> IO ()
 662setReceiveTimeout = setInt32OptFromRestricted B.receiveTimeout
 663
 664-- | <http://api.zeromq.org/4-0:zmq-setsockopt zmq_setsockopt ZMQ_ROUTER_MANDATORY>.
 665setRouterMandatory :: Bool -> Socket Router -> IO ()
 666setRouterMandatory x s = setIntOpt s B.routerMandatory (bool2cint x)
 667
 668-- | <http://api.zeromq.org/4-0:zmq-setsockopt zmq_setsockopt ZMQ_SNDTIMEO>.
 669setSendTimeout :: Integral i => Restricted (Nneg1, Int32) i -> Socket a -> IO ()
 670setSendTimeout = setInt32OptFromRestricted B.sendTimeout
 671
 672-- | <http://api.zeromq.org/4-0:zmq-setsockopt zmq_setsockopt ZMQ_RATE>.
 673setRate :: Integral i => Restricted (N1, Int32) i -> Socket a -> IO ()
 674setRate = setInt32OptFromRestricted B.rate
 675
 676-- | <http://api.zeromq.org/4-0:zmq-setsockopt zmq_setsockopt ZMQ_MULTICAST_HOPS>.
 677setMcastHops :: Integral i => Restricted (N1, Int32) i -> Socket a -> IO ()
 678setMcastHops = setInt32OptFromRestricted B.mcastHops
 679
 680-- | <http://api.zeromq.org/4-0:zmq-setsockopt zmq_setsockopt ZMQ_BACKLOG>.
 681setBacklog :: Integral i => Restricted (N0, Int32) i -> Socket a -> IO ()
 682setBacklog = setInt32OptFromRestricted B.backlog
 683
 684-- | <http://api.zeromq.org/4-0:zmq-setsockopt zmq_setsockopt ZMQ_CURVE_PUBLICKEY>.
 685setCurvePublicKey :: KeyFormat f -> Restricted f SB.ByteString -> Socket a -> IO ()
 686setCurvePublicKey _ k s = setByteStringOpt s B.curvePublicKey (rvalue k)
 687
 688-- | <http://api.zeromq.org/4-0:zmq-setsockopt zmq_setsockopt ZMQ_CURVE_SECRETKEY>.
 689setCurveSecretKey :: KeyFormat f -> Restricted f SB.ByteString -> Socket a -> IO ()
 690setCurveSecretKey _ k s = setByteStringOpt s B.curveSecretKey (rvalue k)
 691
 692-- | <http://api.zeromq.org/4-0:zmq-setsockopt zmq_setsockopt ZMQ_CURVE_SERVERKEY>.
 693setCurveServerKey :: KeyFormat f -> Restricted f SB.ByteString -> Socket a -> IO ()
 694setCurveServerKey _ k s = setByteStringOpt s B.curveServerKey (rvalue k)
 695
 696-- | <http://api.zeromq.org/4-0:zmq-setsockopt zmq_setsockopt ZMQ_PROBE_ROUTER>.
 697setProbeRouter :: SendProbe a => Bool -> Socket a -> IO ()
 698setProbeRouter x s = setIntOpt s B.probeRouter (bool2cint x)
 699
 700-- | <http://api.zeromq.org/4-0:zmq-setsockopt zmq_setsockopt ZMQ_RCVBUF>.
 701setReceiveBuffer :: Integral i => Restricted (N0, Int32) i -> Socket a -> IO ()
 702setReceiveBuffer = setInt32OptFromRestricted B.receiveBuf
 703
 704-- | <http://api.zeromq.org/4-0:zmq-setsockopt zmq_setsockopt ZMQ_RECONNECT_IVL>.
 705setReconnectInterval :: Integral i => Restricted (N0, Int32) i -> Socket a -> IO ()
 706setReconnectInterval = setInt32OptFromRestricted B.reconnectIVL
 707
 708-- | <http://api.zeromq.org/4-0:zmq-setsockopt zmq_setsockopt ZMQ_RECONNECT_IVL_MAX>.
 709setReconnectIntervalMax :: Integral i => Restricted (N0, Int32) i -> Socket a -> IO ()
 710setReconnectIntervalMax = setInt32OptFromRestricted B.reconnectIVLMax
 711
 712-- | <http://api.zeromq.org/4-0:zmq-setsockopt zmq_setsockopt ZMQ_REQ_CORRELATE>.
 713setReqCorrelate :: Bool -> Socket Req -> IO ()
 714setReqCorrelate x s = setIntOpt s B.reqCorrelate (bool2cint x)
 715
 716-- | <http://api.zeromq.org/4-0:zmq-setsockopt zmq_setsockopt ZMQ_REQ_RELAXED>.
 717setReqRelaxed :: Bool -> Socket Req -> IO ()
 718setReqRelaxed x s = setIntOpt s B.reqRelaxed (bool2cint x)
 719
 720-- | <http://api.zeromq.org/4-0:zmq-setsockopt zmq_setsockopt ZMQ_SNDBUF>.
 721setSendBuffer :: Integral i => Restricted (N0, Int32) i -> Socket a -> IO ()
 722setSendBuffer = setInt32OptFromRestricted B.sendBuf
 723
 724-- | <http://api.zeromq.org/4-0:zmq-setsockopt zmq_setsockopt ZMQ_RECOVERY_IVL>.
 725setRecoveryInterval :: Integral i => Restricted (N0, Int32) i -> Socket a -> IO ()
 726setRecoveryInterval = setInt32OptFromRestricted B.recoveryIVL
 727
 728-- | <http://api.zeromq.org/4-0:zmq-setsockopt zmq_setsockopt ZMQ_RCVHWM>.
 729setReceiveHighWM :: Integral i => Restricted (N0, Int32) i -> Socket a -> IO ()
 730setReceiveHighWM = setInt32OptFromRestricted B.receiveHighWM
 731
 732-- | <http://api.zeromq.org/4-0:zmq-setsockopt zmq_setsockopt ZMQ_SNDHWM>.
 733setSendHighWM :: Integral i => Restricted (N0, Int32) i -> Socket a -> IO ()
 734setSendHighWM = setInt32OptFromRestricted B.sendHighWM
 735
 736-- | <http://api.zeromq.org/4-0:zmq-setsockopt zmq_setsockopt ZMQ_TCP_ACCEPT_FILTER>.
 737setTcpAcceptFilter :: Maybe SB.ByteString -> Socket a -> IO ()
 738setTcpAcceptFilter Nothing sock = onSocket "setTcpAcceptFilter" sock $ \s ->
 739    throwIfMinus1Retry_ "setStrOpt" $
 740        c_zmq_setsockopt s (optVal tcpAcceptFilter) nullPtr 0
 741setTcpAcceptFilter (Just dat) sock = setByteStringOpt sock tcpAcceptFilter dat
 742
 743-- | <http://api.zeromq.org/4-0:zmq-setsockopt zmq_setsockopt ZMQ_TCP_KEEPALIVE>.
 744setTcpKeepAlive :: Switch -> Socket a -> IO ()
 745setTcpKeepAlive x s = setIntOpt s B.tcpKeepAlive (fromSwitch x :: CInt)
 746
 747-- | <http://api.zeromq.org/4-0:zmq-setsockopt zmq_setsockopt ZMQ_TCP_KEEPALIVE_CNT>.
 748setTcpKeepAliveCount :: Integral i => Restricted (Nneg1, Int32) i -> Socket a -> IO ()
 749setTcpKeepAliveCount = setInt32OptFromRestricted B.tcpKeepAliveCount
 750
 751-- | <http://api.zeromq.org/4-0:zmq-setsockopt zmq_setsockopt ZMQ_TCP_KEEPALIVE_IDLE>.
 752setTcpKeepAliveIdle :: Integral i => Restricted (Nneg1, Int32) i -> Socket a -> IO ()
 753setTcpKeepAliveIdle = setInt32OptFromRestricted B.tcpKeepAliveIdle
 754
 755-- | <http://api.zeromq.org/4-0:zmq-setsockopt zmq_setsockopt ZMQ_TCP_KEEPALIVE_INTVL>.
 756setTcpKeepAliveInterval :: Integral i => Restricted (Nneg1, Int32) i -> Socket a -> IO ()
 757setTcpKeepAliveInterval = setInt32OptFromRestricted B.tcpKeepAliveInterval
 758
 759-- | <http://api.zeromq.org/4-0:zmq-setsockopt zmq_setsockopt ZMQ_XPUB_VERBOSE>.
 760setXPubVerbose :: Bool -> Socket XPub -> IO ()
 761setXPubVerbose x s = setIntOpt s B.xpubVerbose (bool2cint x)
 762
 763-- | Bind the socket to the given address
 764-- (cf. <http://api.zeromq.org/4-0:zmq-bind zmq_bind>).
 765bind :: Socket a -> String -> IO ()
 766bind sock str = onSocket "bind" sock $
 767    throwIfMinus1Retry_ "bind" . withCString str . c_zmq_bind
 768
 769-- | Unbind the socket from the given address
 770-- (cf. <http://api.zeromq.org/4-0:zmq-unbind zmq_unbind>).
 771unbind :: Socket a -> String -> IO ()
 772unbind sock str = onSocket "unbind" sock $
 773    throwIfMinus1Retry_ "unbind" . withCString str . c_zmq_unbind
 774
 775-- | Connect the socket to the given address
 776-- (cf. <http://api.zeromq.org/4-0:zmq-connect zmq_connect>).
 777connect :: Socket a -> String -> IO ()
 778connect sock str = onSocket "connect" sock $
 779    throwIfMinus1Retry_ "connect" . withCString str . c_zmq_connect
 780
 781-- | Disconnect the socket from the given endpoint
 782-- (cf. <http://api.zeromq.org/4-0:zmq-disconnect zmq_disconnect>).
 783disconnect :: Socket a -> String -> IO ()
 784disconnect sock str = onSocket "disconnect" sock $
 785    throwIfMinus1Retry_ "disconnect" . withCString str . c_zmq_disconnect
 786
 787-- | Send the given 'SB.ByteString' over the socket
 788-- (cf. <http://api.zeromq.org/4-0:zmq-sendmsg zmq_sendmsg>).
 789--
 790-- /Note/: This function always calls @zmq_sendmsg@ in a non-blocking way,
 791-- i.e. there is no need to provide the @ZMQ_DONTWAIT@ flag as this is used
 792-- by default. Still 'send' is blocking the thread as long as the message
 793-- can not be queued on the socket using GHC's 'threadWaitWrite'.
 794send :: Sender a => Socket a -> [Flag] -> SB.ByteString -> IO ()
 795send sock fls val = bracketOnError (messageOf val) messageClose $ \m -> do
 796    onSocket "send" sock $ \s ->
 797        retry "send" (waitWrite sock) $
 798#ifdef mingw32_HOST_OS
 799            c_zmq_sendmsg s (msgPtr m) (combineFlags fls)
 800#else
 801            c_zmq_sendmsg s (msgPtr m) (combineFlags (DontWait : fls))
 802#endif
 803    messageFree m
 804
 805-- | Send the given 'LB.ByteString' over the socket
 806-- (cf. <http://api.zeromq.org/4-0:zmq-sendmsg zmq_sendmsg>).
 807--
 808-- This is operationally identical to @send socket (Strict.concat
 809-- (Lazy.toChunks lbs)) flags@ but may be more efficient.
 810--
 811-- /Note/: This function always calls @zmq_sendmsg@ in a non-blocking way,
 812-- i.e. there is no need to provide the @ZMQ_DONTWAIT@ flag as this is used
 813-- by default. Still 'send'' is blocking the thread as long as the message
 814-- can not be queued on the socket using GHC's 'threadWaitWrite'.
 815send' :: Sender a => Socket a -> [Flag] -> LB.ByteString -> IO ()
 816send' sock fls val = bracketOnError (messageOfLazy val) messageClose $ \m -> do
 817    onSocket "send'" sock $ \s ->
 818        retry "send'" (waitWrite sock) $
 819#ifdef mingw32_HOST_OS
 820            c_zmq_sendmsg s (msgPtr m) (combineFlags fls)
 821#else
 822            c_zmq_sendmsg s (msgPtr m) (combineFlags (DontWait : fls))
 823#endif
 824    messageFree m
 825
 826-- | Send a multi-part message.
 827-- This function applies the 'SendMore' 'Flag' between all message parts.
 828-- 0MQ guarantees atomic delivery of a multi-part message
 829-- (cf. <http://api.zeromq.org/4-0:zmq-sendmsg zmq_sendmsg>).
 830sendMulti :: Sender a => Socket a -> NonEmpty SB.ByteString -> IO ()
 831sendMulti sock msgs = do
 832    mapM_ (send sock [SendMore]) (S.init msgs)
 833    send sock [] (S.last msgs)
 834
 835-- | Receive a 'ByteString' from socket
 836-- (cf. <http://api.zeromq.org/4-0:zmq-recvmsg zmq_recvmsg>).
 837--
 838-- /Note/: This function always calls @zmq_recvmsg@ in a non-blocking way,
 839-- i.e. there is no need to provide the @ZMQ_DONTWAIT@ flag as this is used
 840-- by default. Still 'receive' is blocking the thread as long as no data
 841-- is available using GHC's 'threadWaitRead'.
 842receive :: Receiver a => Socket a -> IO (SB.ByteString)
 843receive sock = bracket messageInit messageClose $ \m ->
 844  onSocket "receive" sock $ \s -> do
 845    retry "receive" (waitRead sock) $
 846#ifdef mingw32_HOST_OS
 847          c_zmq_recvmsg s (msgPtr m) 0
 848#else
 849          c_zmq_recvmsg s (msgPtr m) (flagVal dontWait)
 850#endif
 851    data_ptr <- c_zmq_msg_data (msgPtr m)
 852    size     <- c_zmq_msg_size (msgPtr m)
 853    SB.packCStringLen (data_ptr, fromIntegral size)
 854
 855-- | Receive a multi-part message.
 856-- This function collects all message parts send via 'sendMulti'.
 857receiveMulti :: Receiver a => Socket a -> IO [SB.ByteString]
 858receiveMulti sock = recvall []
 859  where
 860    recvall acc = do
 861        msg <- receive sock
 862        moreToReceive sock >>= next (msg:acc)
 863
 864    next acc True  = recvall acc
 865    next acc False = return (reverse acc)
 866
 867-- | Setup socket monitoring, i.e. a 'Pair' socket which
 868-- sends monitoring events about the given 'Socket' to the
 869-- given address.
 870socketMonitor :: [EventType] -> String -> Socket a -> IO ()
 871socketMonitor es addr soc = onSocket "socketMonitor" soc $ \s ->
 872    withCString addr $ \a ->
 873        throwIfMinus1_ "zmq_socket_monitor" $
 874            c_zmq_socket_monitor s a (events2cint es)
 875
 876-- | Monitor socket events
 877-- (cf. <http://api.zeromq.org/4-0:zmq-socket-monitor zmq_socket_monitor>).
 878--
 879-- This function returns a function which can be invoked to retrieve
 880-- the next socket event, potentially blocking until the next one becomes
 881-- available. When applied to 'False', monitoring will terminate, i.e.
 882-- internal monitoring resources will be disposed. Consequently after
 883-- 'monitor' has been invoked, the returned function must be applied
 884-- /once/ to 'False'.
 885monitor :: [EventType] -> Context -> Socket a -> IO (Bool -> IO (Maybe EventMsg))
 886monitor es ctx sock = do
 887    let addr = "inproc://" ++ show (_socket . _socketRepr $ sock)
 888    s <- socket ctx Pair
 889    socketMonitor es addr sock
 890    connect s addr
 891    next s <$> messageInit
 892  where
 893    next soc m False = messageClose m `finally` close soc >> return Nothing
 894    next soc m True  = onSocket "recv" soc $ \s -> do
 895        retry "recv" (waitRead soc) $
 896#ifdef mingw32_HOST_OS
 897            c_zmq_recvmsg s (msgPtr m) 0
 898#else
 899            c_zmq_recvmsg s (msgPtr m) (flagVal dontWait)
 900#endif
 901        evt <- peekZMQEvent (msgPtr m)
 902        str <- receive soc
 903        return . Just $ eventMessage str evt
 904
 905-- | Polls for events on the given 'Poll' descriptors. Returns a list of
 906-- events per descriptor which have occured.
 907-- (cf. <http://api.zeromq.org/4-0:zmq-poll zmq_poll>)
 908poll :: (SocketLike s, MonadIO m) => Timeout -> [Poll s m] -> m [[Event]]
 909poll _    [] = return []
 910poll to desc = do
 911    let len = length desc
 912    let ps  = map toZMQPoll desc
 913    ps' <- liftIO $ withArray ps $ \ptr -> do
 914        throwIfMinus1Retry_ "poll" $
 915            c_zmq_poll ptr (fromIntegral len) (fromIntegral to)
 916        peekArray len ptr
 917    mapM fromZMQPoll (zip desc ps')
 918  where
 919    toZMQPoll :: (SocketLike s, MonadIO m) => Poll s m -> ZMQPoll
 920    toZMQPoll (Sock s e _) =
 921        ZMQPoll (_socket . _socketRepr . toSocket $ s) 0 (combine (map fromEvent e)) 0
 922
 923    toZMQPoll (File (Fd s) e _) =
 924        ZMQPoll nullPtr (fromIntegral s) (combine (map fromEvent e)) 0
 925
 926    fromZMQPoll :: (SocketLike s, MonadIO m) => (Poll s m, ZMQPoll) -> m [Event]
 927    fromZMQPoll (p, zp) = do
 928        let e = toEvents . fromIntegral . pRevents $ zp
 929        let (e', f) = case p of
 930                        (Sock _ x g) -> (x, g)
 931                        (File _ x g) -> (x, g)
 932        forM f (unless (P.null (e `intersect` e')) . ($ e)) >> return e
 933
 934    fromEvent :: Event -> CShort
 935    fromEvent In   = fromIntegral . pollVal $ pollIn
 936    fromEvent Out  = fromIntegral . pollVal $ pollOut
 937    fromEvent Err  = fromIntegral . pollVal $ pollerr
 938
 939-- Convert bit-masked word into Event list.
 940toEvents :: Word32 -> [Event]
 941toEvents e = foldl' (\es f -> f e es) [] tests
 942  where
 943      tests =
 944        [ \i xs -> if i .&. (fromIntegral . pollVal $ pollIn)  /= 0 then In:xs else xs
 945        , \i xs -> if i .&. (fromIntegral . pollVal $ pollOut) /= 0 then Out:xs else xs
 946        , \i xs -> if i .&. (fromIntegral . pollVal $ pollerr) /= 0 then Err:xs else xs
 947        ]
 948
 949retry :: String -> IO () -> IO CInt -> IO ()
 950retry msg wait act = throwIfMinus1RetryMayBlock_ msg act wait
 951
 952wait' :: ZMQPollEvent -> Socket a -> IO ()
 953#ifdef mingw32_HOST_OS
 954wait' _ _ = return ()
 955#else
 956wait' p s = do
 957    e <- getInt32Option B.events s
 958    unless (testev e) $ do
 959        fd <- getIntOpt s B.filedesc 0
 960        threadWaitRead (Fd fd)
 961        wait' p s
 962  where
 963    testev e = e .&. fromIntegral (pollVal p) /= 0
 964#endif
 965
 966-- | Wait until data is available for reading from the given Socket.
 967-- After this function returns, a call to 'receive' will essentially be
 968-- non-blocking.
 969waitRead :: Socket a -> IO ()
 970waitRead = wait' pollIn
 971
 972-- | Wait until data can be written to the given Socket.
 973-- After this function returns, a call to 'send' will essentially be
 974-- non-blocking.
 975waitWrite :: Socket a -> IO ()
 976waitWrite = wait' pollOut
 977
 978-- | Starts built-in 0MQ proxy
 979-- (cf. <http://api.zeromq.org/4-0:zmq-proxy zmq_proxy>)
 980--
 981-- Proxy connects front to back socket
 982--
 983-- Before calling proxy all sockets should be bound
 984--
 985-- If the capture socket is not Nothing, the proxy  shall send all
 986-- messages, received on both frontend and backend, to the capture socket.
 987proxy :: Socket a -> Socket b -> Maybe (Socket c) -> IO ()
 988proxy front back capture =
 989    onSocket "proxy-front" front $ \f ->
 990    onSocket "proxy-back"  back  $ \b ->
 991        throwIfMinus1Retry_ "c_zmq_proxy" $ c_zmq_proxy f b c
 992  where
 993    c = maybe nullPtr (_socket . _socketRepr) capture
 994
 995-- | Generate a new curve key pair.
 996-- (cf. <http://api.zeromq.org/4-0:zmq-curve-keypair zmq_curve_keypair>)
 997curveKeyPair :: MonadIO m => m (Restricted Div5 SB.ByteString, Restricted Div5 SB.ByteString)
 998curveKeyPair = liftIO $
 999    allocaBytes 41 $ \cstr1 ->
1000    allocaBytes 41 $ \cstr2 -> do
1001        throwIfMinus1_ "c_zmq_curve_keypair" $ c_zmq_curve_keypair cstr1 cstr2
1002        public  <- toRestricted <$> SB.packCString cstr1
1003        private <- toRestricted <$> SB.packCString cstr2
1004        maybe (fail errmsg) return ((,) <$> public <*> private)
1005      where
1006        errmsg = "curveKeyPair: invalid key-lengths produced"
1007