Skip to content
This repository has been archived by the owner on Apr 4, 2018. It is now read-only.

Commit

Permalink
Introduce typed enpoint representations.
Browse files Browse the repository at this point in the history
Instead of using plain Strings to denote endpoints for bind/connect, we
add a new module Data.Endpoint which includes types for the various
transport endpoint addresses.

Since these types are instances of IsString, client code can continue to
use strings if the OverloadedStrings language extension is enabled.
  • Loading branch information
Toralf Wittner committed Dec 31, 2011
1 parent b3d39f3 commit 3d9ae98
Show file tree
Hide file tree
Showing 4 changed files with 109 additions and 7 deletions.
94 changes: 94 additions & 0 deletions src/Data/Endpoint.hs
@@ -0,0 +1,94 @@
module Data.Endpoint (
Endpoint (..)
, TcpAddress (..)
, PgmAddress (..)
) where

import Control.Applicative
import Data.IP
import Data.Word
import Data.Char (isDigit)
import Data.String
import Text.Printf
import Text.Read (lift, readPrec)
import Text.ParserCombinators.ReadP

-- | An Endpoint is used in 'connect' and 'bind' calls and specifies
-- a transport plus address data.
data Endpoint =
InProc String -- ^ cf. zmq_inproc (7)
| IPC String -- ^ cf. zmq_ipc (7)
| TCP TcpAddress -- ^ cf. zmq_tcp (7)
| PGM PgmAddress -- ^ cf. zmq_pgm (7)
| EPGM PgmAddress -- ^ cf. zmq_pgm (7)
deriving Eq

-- | A TcpAddress is either an IP address (IPv4 or IPv6) plus a port
-- number, or an interface name (use @\"*\"@ to refer to all interfaces) plus
-- port number.
data TcpAddress =
TAddr IP Word16 -- ^ IPv{4,6} address and port number.
| TIface String Word16 -- ^ Interface name and port number.
deriving Eq

-- | A (E)PGM address representation.
data PgmAddress =
PAddr IP IP Word16 -- ^ Interface IP address ';' Multicast IP address ':' port
| PIface String IP Word16 -- ^ Interface name ';' Multicast IP address ':' port
deriving Eq

instance Show Endpoint where
show (InProc x) = printf "inproc://%s" x
show (IPC x) = printf "ipc://%s" x
show (TCP x) = printf "tcp://%s" (show x)
show (PGM x) = printf "pgm://%s" (show x)
show (EPGM x) = printf "epgm://%s" (show x)

instance Show TcpAddress where
show (TAddr ip port) = printf "%s:%u" (show ip) port
show (TIface name port) = printf "%s:%u" name port

instance Show PgmAddress where
show (PAddr ip mc port) = printf "%s;%s:%u" (show ip) (show mc) port
show (PIface name mc port) = printf "%s;%s:%u" name (show mc) port

instance Read Endpoint where
readPrec = lift readEndpoint

instance Read TcpAddress where
readPrec = lift readTcpAddress

instance Read PgmAddress where
readPrec = lift readPgmAddress

instance IsString Endpoint where
fromString = read

instance IsString TcpAddress where
fromString = read

instance IsString PgmAddress where
fromString = read

readEndpoint :: ReadP Endpoint
readEndpoint =
(string "tcp://" >> TCP <$> readTcpAddress)
+++ (string "ipc://" >> IPC <$> many1 get)
+++ (string "inproc://" >> InProc <$> many1 get)
+++ (string "pgm://" >> PGM <$> readPgmAddress)
+++ (string "epgm://" >> EPGM <$> readPgmAddress)

readTcpAddress :: ReadP TcpAddress
readTcpAddress = do
(ip:port:[]) <- (many1 get) `sepBy1` (char ':')
if isDigit (head ip)
then return $ TAddr (read ip) (read port)
else return $ TIface ip (read port)

readPgmAddress :: ReadP PgmAddress
readPgmAddress = do
(ip:mc:port:[]) <- (many1 get) `sepBy1` (char ';' +++ char ':')
if isDigit (head ip)
then return $ PAddr (read ip) (read mc) (read port)
else return $ PIface ip (read mc) (read port)

17 changes: 11 additions & 6 deletions src/System/ZMQ3.hs
Expand Up @@ -93,6 +93,10 @@ module System.ZMQ3 (
, Data.Restricted.restrict
, Data.Restricted.toRestricted

, Data.Endpoint.Endpoint (..)
, Data.Endpoint.TcpAddress (..)
, Data.Endpoint.PgmAddress (..)

-- * Low-level functions
, init
, term
Expand All @@ -106,6 +110,7 @@ import Control.Applicative
import Control.Exception
import Control.Monad (unless, when)
import Data.Restricted
import Data.Endpoint
import Data.IORef (atomicModifyIORef)
import Foreign
import Foreign.C.Error
Expand Down Expand Up @@ -463,14 +468,14 @@ setSendHighWM :: Integral i => Restricted N0 Int32 i -> Socket a -> IO ()
setSendHighWM = setInt32OptFromRestricted B.sendHighWM

-- | Bind the socket to the given address (zmq_bind)
bind :: Socket a -> String -> IO ()
bind sock str = onSocket "bind" sock $
throwErrnoIfMinus1_ "bind" . withCString str . c_zmq_bind
bind :: Socket a -> Endpoint -> IO ()
bind sock ep = onSocket "bind" sock $
throwErrnoIfMinus1_ "bind" . withCString (show ep) . c_zmq_bind

-- | Connect the socket to the given address (zmq_connect).
connect :: Socket a -> String -> IO ()
connect sock str = onSocket "connect" sock $
throwErrnoIfMinus1_ "connect" . withCString str . c_zmq_connect
connect :: Socket a -> Endpoint -> IO ()
connect sock ep = onSocket "connect" sock $
throwErrnoIfMinus1_ "connect" . withCString (show ep) . c_zmq_connect

-- | Send the given 'SB.ByteString' over the socket (zmq_sendmsg).
send :: Socket a -> [Flag] -> SB.ByteString -> IO ()
Expand Down
2 changes: 1 addition & 1 deletion tests/System/ZMQ3/Test/Properties.hs
@@ -1,4 +1,4 @@
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FlexibleInstances, OverloadedStrings #-}
module System.ZMQ3.Test.Properties where

import Control.Applicative
Expand Down
3 changes: 3 additions & 0 deletions zeromq3-haskell.cabal
Expand Up @@ -33,6 +33,7 @@ library
exposed-modules: System.ZMQ3, Data.Restricted
other-modules: System.ZMQ3.Base
, System.ZMQ3.Internal
, Data.Endpoint
includes: zmq.h
ghc-options: -Wall -O2
extensions: CPP
Expand All @@ -41,6 +42,7 @@ library
build-depends: base >= 3 && < 5
, containers
, bytestring
, iproute >= 1.2.4

if os(freebsd)
extra-libraries: zmq, pthread
Expand All @@ -54,6 +56,7 @@ test-suite zeromq-haskell-tests
build-depends: zeromq3-haskell
, base >= 3 && < 5
, containers
, iproute >= 1.2.4
, bytestring
, test-framework >= 0.4
, test-framework-quickcheck2 >= 0.2
Expand Down

0 comments on commit 3d9ae98

Please sign in to comment.