Add support for Unix domain socket connection

Update corresponding parser in readHostPortM
Update showHostPort
This commit is contained in:
horus 2019-09-11 14:08:22 +08:00
parent 76d5f84f8a
commit 4d1b2a0108
2 changed files with 38 additions and 11 deletions

View file

@ -29,10 +29,10 @@ import Data.List (intersect, partition, (\\), delete)
import Control.Applicative ((<$>)) import Control.Applicative ((<$>))
#endif #endif
import Control.Monad (forM_) import Control.Monad (forM_, guard)
import System.IO.Unsafe (unsafePerformIO) import System.IO.Unsafe (unsafePerformIO)
import System.Timeout (timeout) import System.Timeout (timeout)
import Text.ParserCombinators.Parsec (parse, many1, letter, digit, char, eof, import Text.ParserCombinators.Parsec (parse, many1, letter, digit, char, anyChar, eof,
spaces, try, (<|>)) spaces, try, (<|>))
import qualified Data.List as List import qualified Data.List as List
@ -76,14 +76,15 @@ host hostname = Host hostname defaultPort
showHostPort :: Host -> String showHostPort :: Host -> String
-- ^ Display host as \"host:port\" -- ^ Display host as \"host:port\"
-- TODO: Distinguish Service and UnixSocket port -- TODO: Distinguish Service port
showHostPort (Host hostname port) = hostname ++ ":" ++ portname where showHostPort (Host hostname (PortNumber port)) = hostname ++ ":" ++ show port
portname = case port of #if !defined(mingw32_HOST_OS) && !defined(cygwin32_HOST_OS) && !defined(_WIN32)
PortNumber p -> show p showHostPort (Host _ (UnixSocket path)) = "unix:" ++ path
#endif
readHostPortM :: (Monad m) => String -> m Host readHostPortM :: (Monad m) => String -> m Host
-- ^ Read string \"hostname:port\" as @Host hosthame (PortNumber port)@ or \"hostname\" as @host hostname@ (default port). Fail if string does not match either syntax. -- ^ Read string \"hostname:port\" as @Host hosthame (PortNumber port)@ or \"hostname\" as @host hostname@ (default port). Fail if string does not match either syntax.
-- TODO: handle Service and UnixSocket port -- TODO: handle Service port
readHostPortM = either (fail . show) return . parse parser "readHostPort" where readHostPortM = either (fail . show) return . parse parser "readHostPort" where
hostname = many1 (letter <|> digit <|> char '-' <|> char '.') hostname = many1 (letter <|> digit <|> char '-' <|> char '.')
parser = do parser = do
@ -91,9 +92,15 @@ readHostPortM = either (fail . show) return . parse parser "readHostPort" where
h <- hostname h <- hostname
try (spaces >> eof >> return (host h)) <|> do try (spaces >> eof >> return (host h)) <|> do
_ <- char ':' _ <- char ':'
port :: Int <- read <$> many1 digit try ( do port :: Int <- read <$> many1 digit
spaces >> eof spaces >> eof
return $ Host h (PortNumber $ fromIntegral port) return $ Host h (PortNumber $ fromIntegral port))
#if !defined(mingw32_HOST_OS) && !defined(cygwin32_HOST_OS) && !defined(_WIN32)
<|> do guard (h == "unix")
p <- many1 anyChar
eof
return $ Host "" (UnixSocket p)
#endif
readHostPort :: String -> Host readHostPort :: String -> Host
-- ^ Read string \"hostname:port\" as @Host hostname (PortNumber port)@ or \"hostname\" as @host hostname@ (default port). Error if string does not match either syntax. -- ^ Read string \"hostname:port\" as @Host hostname (PortNumber port)@ or \"hostname\" as @host hostname@ (default port). Error if string does not match either syntax.

View file

@ -21,7 +21,11 @@ import System.IO (Handle, IOMode(ReadWriteMode))
-- | Wraps network's 'PortNumber' -- | Wraps network's 'PortNumber'
-- Used to ease compatibility between older and newer network versions. -- Used to ease compatibility between older and newer network versions.
newtype PortID = PortNumber N.PortNumber deriving (Enum, Eq, Integral, Num, Ord, Read, Real, Show) data PortID = PortNumber N.PortNumber
#if !defined(mingw32_HOST_OS) && !defined(cygwin32_HOST_OS) && !defined(_WIN32)
| UnixSocket String
#endif
deriving (Eq, Ord, Show)
#if !MIN_VERSION_network(2, 9, 0) #if !MIN_VERSION_network(2, 9, 0)
@ -32,6 +36,10 @@ connectTo :: N.HostName -- Hostname
-> IO Handle -- Connected Socket -> IO Handle -- Connected Socket
connectTo hostname (PortNumber port) = N.connectTo hostname (N.PortNumber port) connectTo hostname (PortNumber port) = N.connectTo hostname (N.PortNumber port)
#if !defined(mingw32_HOST_OS) && !defined(cygwin32_HOST_OS) && !defined(_WIN32)
connectTo _ (UnixSocket path) = N.connectTo "" (N.UnixSocket path)
#endif
#else #else
-- Copied implementation from network 2.8's 'connectTo', but using our 'PortID' newtype. -- Copied implementation from network 2.8's 'connectTo', but using our 'PortID' newtype.
@ -49,4 +57,16 @@ connectTo hostname (PortNumber port) = do
N.connect sock (N.SockAddrInet port (hostAddress he)) N.connect sock (N.SockAddrInet port (hostAddress he))
N.socketToHandle sock ReadWriteMode N.socketToHandle sock ReadWriteMode
) )
#if !defined(mingw32_HOST_OS) && !defined(cygwin32_HOST_OS) && !defined(_WIN32)
connectTo _ (UnixSocket path) = do
bracketOnError
(N.socket N.AF_UNIX N.Stream 0)
(N.close)
(\sock -> do
N.connect sock (N.SockAddrUnix path)
N.socketToHandle sock ReadWriteMode
)
#endif
#endif #endif