/src/System/ZMQ4.hs
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