|
@@ -2,11 +2,7 @@
|
|
|
{-# LANGUAGE ExistentialQuantification #-}
|
|
|
{-# LANGUAGE ForeignFunctionInterface #-}
|
|
|
|
|
|
--- |
|
|
|
--- Filelike provides a typeclass for Unix style "everything is a file" IO,
|
|
|
--- and implementations for abstracting standard IO, files and network connections.
|
|
|
--- This module also provides TLS wraping over other filelike types.
|
|
|
-module System.IO.Uniform.Targets (TlsSettings(..), UniformIO(..), SocketIO, FileIO, TlsStream, BoundPort, SomeIO(..), connectTo, connectToHost, bindPort, accept, openFile, getPeer, closePort) where
|
|
|
+module System.IO.Uniform.Targets (TlsSettings(..), UniformIO(..), SocketIO, FileIO, TlsStream, BoundedPort, SomeIO(..), connectTo, connectToHost, bindPort, accept, openFile, getPeer, closePort) where
|
|
|
|
|
|
import Foreign
|
|
|
import Foreign.C.Types
|
|
@@ -29,24 +25,29 @@ instance Default TlsSettings where
|
|
|
def = TlsSettings "" ""
|
|
|
|
|
|
-- |
|
|
|
--- Typeclass for IO objects that behave like a Unix file (independent of seeking support).
|
|
|
+-- Typeclass for uniform IO targets.
|
|
|
class UniformIO a where
|
|
|
- -- | fRead fd n
|
|
|
- -- Reads a block of at most n bytes of data from the filelike object fd.
|
|
|
+ -- | uRead fd n
|
|
|
+ --
|
|
|
+ -- Reads a block of at most n bytes of data from the IO target.
|
|
|
-- Reading will block if there's no data available, but will return immediately
|
|
|
-- if any amount of data is availble.
|
|
|
- fRead :: a -> Int -> IO ByteString
|
|
|
- -- | fPut fd text
|
|
|
- -- Writes all the bytes of text into the filelike object. Takes care of retrying if needed.
|
|
|
- fPut :: a -> ByteString -> IO ()
|
|
|
+ uRead :: a -> Int -> IO ByteString
|
|
|
+ -- | uPut fd text
|
|
|
+ --
|
|
|
+ -- Writes all the bytes of text into the IO target. Takes care of retrying if needed.
|
|
|
+ uPut :: a -> ByteString -> IO ()
|
|
|
-- | fClose fd
|
|
|
- -- Closes the filelike object, releasing any allocated resource. Resources may leak if not called
|
|
|
+ --
|
|
|
+ -- Closes the IO target, releasing any allocated resource. Resources may leak if not called
|
|
|
-- for every oppened fd.
|
|
|
- fClose :: a -> IO ()
|
|
|
+ uClose :: a -> IO ()
|
|
|
-- | startTLS fd
|
|
|
- -- Starts a TLS connection over the filelike object.
|
|
|
+ --
|
|
|
+ -- Starts a TLS connection over the IO target.
|
|
|
startTls :: TlsSettings -> a -> IO TlsStream
|
|
|
-- | isSecure fd
|
|
|
+ --
|
|
|
-- Indicates whether the data written or read from fd is secure at transport.
|
|
|
isSecure :: a -> Bool
|
|
|
|
|
@@ -54,15 +55,15 @@ class UniformIO a where
|
|
|
data SomeIO = forall a. (UniformIO a) => SomeIO a
|
|
|
|
|
|
instance UniformIO SomeIO where
|
|
|
- fRead (SomeIO s) n = fRead s n
|
|
|
- fPut (SomeIO s) t = fPut s t
|
|
|
- fClose (SomeIO s) = fClose s
|
|
|
+ uRead (SomeIO s) n = uRead s n
|
|
|
+ uPut (SomeIO s) t = uPut s t
|
|
|
+ uClose (SomeIO s) = uClose s
|
|
|
startTls set (SomeIO s) = startTls set s
|
|
|
isSecure (SomeIO s) = isSecure s
|
|
|
|
|
|
data Nethandler
|
|
|
--- | A bound IP port from where to accept SocketIO connections.
|
|
|
-newtype BoundPort = BoundPort {lis :: (Ptr Nethandler)}
|
|
|
+-- | A bounded IP port from where to accept SocketIO connections.
|
|
|
+newtype BoundedPort = BoundedPort {lis :: (Ptr Nethandler)}
|
|
|
data SockDs
|
|
|
newtype SocketIO = SocketIO {sock :: (Ptr SockDs)}
|
|
|
data FileDs
|
|
@@ -72,21 +73,21 @@ newtype TlsStream = TlsStream {tls :: (Ptr TlsDs)}
|
|
|
|
|
|
-- | UniformIO IP connections.
|
|
|
instance UniformIO SocketIO where
|
|
|
- fRead s n = allocaArray n (
|
|
|
+ uRead s n = allocaArray n (
|
|
|
\b -> do
|
|
|
count <- c_recvSock (sock s) b (fromIntegral n)
|
|
|
if count < 0
|
|
|
then throwErrno "could not read"
|
|
|
else BS.packCStringLen (b, fromIntegral count)
|
|
|
)
|
|
|
- fPut s t = BS.useAsCStringLen t (
|
|
|
+ uPut s t = BS.useAsCStringLen t (
|
|
|
\(str, n) -> do
|
|
|
count <- c_sendSock (sock s) str $ fromIntegral n
|
|
|
if count < 0
|
|
|
then throwErrno "could not write"
|
|
|
else return ()
|
|
|
)
|
|
|
- fClose s = c_closeSock (sock s)
|
|
|
+ uClose s = c_closeSock (sock s)
|
|
|
startTls st s = withCString (tlsCertificateChainFile st) (
|
|
|
\cert -> withCString (tlsPrivateKeyFile st) (
|
|
|
\key -> do
|
|
@@ -100,46 +101,48 @@ instance UniformIO SocketIO where
|
|
|
|
|
|
-- | UniformIO type for file IO.
|
|
|
instance UniformIO FileIO where
|
|
|
- fRead s n = allocaArray n (
|
|
|
+ uRead s n = allocaArray n (
|
|
|
\b -> do
|
|
|
count <- c_recvFile (fd s) b $ fromIntegral n
|
|
|
if count < 0
|
|
|
then throwErrno "could not read"
|
|
|
else BS.packCStringLen (b, fromIntegral count)
|
|
|
)
|
|
|
- fPut s t = BS.useAsCStringLen t (
|
|
|
+ uPut s t = BS.useAsCStringLen t (
|
|
|
\(str, n) -> do
|
|
|
count <- c_sendFile (fd s) str $ fromIntegral n
|
|
|
if count < 0
|
|
|
then throwErrno "could not write"
|
|
|
else return ()
|
|
|
)
|
|
|
- fClose s = c_closeFile (fd s)
|
|
|
+ uClose s = c_closeFile (fd s)
|
|
|
-- Not implemented yet.
|
|
|
startTls _ _ = return . TlsStream $ nullPtr
|
|
|
isSecure _ = False
|
|
|
|
|
|
--- | UniformIO wrapper that applies TLS to communication on filelike objects.
|
|
|
+-- | UniformIO wrapper that applies TLS to communication on IO target.
|
|
|
+-- This type is constructed by calling startTls on other targets.
|
|
|
instance UniformIO TlsStream where
|
|
|
- fRead s n = allocaArray n (
|
|
|
+ uRead s n = allocaArray n (
|
|
|
\b -> do
|
|
|
count <- c_recvTls (tls s) b $ fromIntegral n
|
|
|
if count < 0
|
|
|
then throwErrno "could not read"
|
|
|
else BS.packCStringLen (b, fromIntegral count)
|
|
|
)
|
|
|
- fPut s t = BS.useAsCStringLen t (
|
|
|
+ uPut s t = BS.useAsCStringLen t (
|
|
|
\(str, n) -> do
|
|
|
count <- c_sendTls (tls s) str $ fromIntegral n
|
|
|
if count < 0
|
|
|
then throwErrno "could not write"
|
|
|
else return ()
|
|
|
)
|
|
|
- fClose s = c_closeTls (tls s)
|
|
|
+ uClose s = c_closeTls (tls s)
|
|
|
startTls _ s = return s
|
|
|
isSecure _ = True
|
|
|
|
|
|
-- | connectToHost hostName port
|
|
|
+--
|
|
|
-- Connects to the given host and port.
|
|
|
connectToHost :: String -> Int -> IO SocketIO
|
|
|
connectToHost host port = do
|
|
@@ -158,6 +161,7 @@ connectToHost host port = do
|
|
|
|
|
|
|
|
|
-- | ConnecctTo ipAddress port
|
|
|
+--
|
|
|
-- Connects to the given port of the host at the given IP address.
|
|
|
connectTo :: IP.IP -> Int -> IO SocketIO
|
|
|
connectTo host port = do
|
|
@@ -187,17 +191,18 @@ connectTo host port = do
|
|
|
-- | bindPort port
|
|
|
-- Binds to the given IP port, becoming ready to accept connections on it.
|
|
|
-- Binding to port numbers under 1024 will fail unless performed by the superuser,
|
|
|
--- once bound, a process can reduce its privileges and still accept clients on that port.
|
|
|
-bindPort :: Int -> IO BoundPort
|
|
|
+-- once bounded, a process can reduce its privileges and still accept clients on that port.
|
|
|
+bindPort :: Int -> IO BoundedPort
|
|
|
bindPort port = do
|
|
|
- r <- fmap BoundPort $ c_getPort $ fromIntegral port
|
|
|
+ r <- fmap BoundedPort $ c_getPort $ fromIntegral port
|
|
|
if lis r == nullPtr
|
|
|
then throwErrno "could not bind to port"
|
|
|
else return r
|
|
|
|
|
|
-- | accept port
|
|
|
+--
|
|
|
-- Accept clients on a port previously bound with bindPort.
|
|
|
-accept :: BoundPort -> IO SocketIO
|
|
|
+accept :: BoundedPort -> IO SocketIO
|
|
|
accept port = do
|
|
|
r <- fmap SocketIO $ c_accept (lis port)
|
|
|
if sock r == nullPtr
|
|
@@ -236,8 +241,8 @@ getPeer s = allocaArray 16 (
|
|
|
)
|
|
|
)
|
|
|
|
|
|
--- | Closes a BoundPort, and releases any resource used by it.
|
|
|
-closePort :: BoundPort -> IO ()
|
|
|
+-- | Closes a BoundedPort, and releases any resource used by it.
|
|
|
+closePort :: BoundedPort -> IO ()
|
|
|
closePort p = c_closePort (lis p)
|
|
|
|
|
|
foreign import ccall "getPort" c_getPort :: CInt -> IO (Ptr Nethandler)
|