Browse Source

Streamline.receiveLine was blocking after the end of line. Fixed.
Added test for detecting a blocking Streamline.receiveLine.

Marcos 8 years ago
parent
commit
792a053542
4 changed files with 74 additions and 21 deletions
  1. 2 3
      src/System/IO/Uniform/Streamline.hs
  2. 18 17
      src/System/IO/Uniform/Targets.hs
  3. 42 0
      test/Lazyness.hs
  4. 12 1
      uniform-io.cabal

+ 2 - 3
src/System/IO/Uniform/Streamline.hs

@@ -15,7 +15,6 @@ import Control.Monad.IO.Class
 import System.IO.Error
 import System.IO.Error
 import Data.ByteString (ByteString)
 import Data.ByteString (ByteString)
 import qualified Data.ByteString as BS
 import qualified Data.ByteString as BS
-import Data.Char (ord)
 import Data.Word8 (Word8)
 import Data.Word8 (Word8)
 import Data.IP (IP)
 import Data.IP (IP)
 
 
@@ -240,7 +239,7 @@ setEcho e = Streamline $ \cl -> return ((), cl{echo=e})
 parseLine :: A.Parser ByteString
 parseLine :: A.Parser ByteString
 parseLine = do
 parseLine = do
   l <- A.takeTill isEol
   l <- A.takeTill isEol
-  (A.string "\r\n" <|> A.string "\n")
+  (A.word8 13 >> A.word8 10) <|>  A.word8 10
   return l
   return l
   
   
 lineWithEol :: A.Parser (ByteString, ByteString)
 lineWithEol :: A.Parser (ByteString, ByteString)
@@ -254,7 +253,7 @@ lineScanner False c = Just $ isEol c
 lineScanner True c = if isEol c then Just True else Nothing
 lineScanner True c = if isEol c then Just True else Nothing
 
 
 isEol :: Word8 -> Bool
 isEol :: Word8 -> Bool
-isEol c = elem c (map (fromIntegral . ord) "\r\n")
+isEol c = c == 13 || c == 10
 
 
 eofError :: MonadIO m => String -> m a
 eofError :: MonadIO m => String -> m a
 eofError msg = liftIO . ioError $ mkIOError eofErrorType msg Nothing Nothing
 eofError msg = liftIO . ioError $ mkIOError eofErrorType msg Nothing Nothing

+ 18 - 17
src/System/IO/Uniform/Targets.hs

@@ -1,6 +1,7 @@
 {-# LANGUAGE OverloadedStrings #-}
 {-# LANGUAGE OverloadedStrings #-}
 {-# LANGUAGE ExistentialQuantification #-}
 {-# LANGUAGE ExistentialQuantification #-}
 {-# LANGUAGE ForeignFunctionInterface #-}
 {-# LANGUAGE ForeignFunctionInterface #-}
+{-# LANGUAGE InterruptibleFFI #-}
 
 
 module System.IO.Uniform.Targets (TlsSettings(..), UniformIO(..), SocketIO, FileIO, TlsStream, BoundedPort, 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
 
 
@@ -245,24 +246,24 @@ getPeer s = allocaArray 16 (
 closePort :: BoundedPort -> IO ()
 closePort :: BoundedPort -> IO ()
 closePort p = c_closePort (lis p)
 closePort p = c_closePort (lis p)
 
 
-foreign import ccall "getPort" c_getPort :: CInt -> IO (Ptr Nethandler)
-foreign import ccall "createFromHandler" c_accept :: Ptr Nethandler -> IO (Ptr SockDs)
-foreign import ccall "createFromFileName" c_createFile :: CString -> IO (Ptr FileDs)
-foreign import ccall "createToIPv4Host" c_connect4 :: CUInt -> CInt -> IO (Ptr SockDs)
-foreign import ccall "createToIPv6Host" c_connect6 :: Ptr CUChar -> CInt -> IO (Ptr SockDs)
+foreign import ccall safe "getPort" c_getPort :: CInt -> IO (Ptr Nethandler)
+foreign import ccall safe "createFromHandler" c_accept :: Ptr Nethandler -> IO (Ptr SockDs)
+foreign import ccall safe "createFromFileName" c_createFile :: CString -> IO (Ptr FileDs)
+foreign import ccall safe "createToIPv4Host" c_connect4 :: CUInt -> CInt -> IO (Ptr SockDs)
+foreign import ccall safe "createToIPv6Host" c_connect6 :: Ptr CUChar -> CInt -> IO (Ptr SockDs)
 
 
-foreign import ccall "startSockTls" c_startSockTls :: Ptr SockDs -> CString -> CString -> IO (Ptr TlsDs)
-foreign import ccall "getPeer" c_getPeer :: Ptr SockDs -> Ptr CUInt -> Ptr CUChar -> Ptr CInt -> IO (CInt)
+foreign import ccall safe "startSockTls" c_startSockTls :: Ptr SockDs -> CString -> CString -> IO (Ptr TlsDs)
+foreign import ccall safe "getPeer" c_getPeer :: Ptr SockDs -> Ptr CUInt -> Ptr CUChar -> Ptr CInt -> IO (CInt)
 
 
-foreign import ccall "closeSockDs" c_closeSock :: Ptr SockDs -> IO ()
-foreign import ccall "closeFileDs" c_closeFile :: Ptr FileDs -> IO ()
-foreign import ccall "closeHandler" c_closePort :: Ptr Nethandler -> IO ()
-foreign import ccall "closeTlsDs" c_closeTls :: Ptr TlsDs -> IO ()
+foreign import ccall safe "closeSockDs" c_closeSock :: Ptr SockDs -> IO ()
+foreign import ccall safe "closeFileDs" c_closeFile :: Ptr FileDs -> IO ()
+foreign import ccall safe "closeHandler" c_closePort :: Ptr Nethandler -> IO ()
+foreign import ccall safe "closeTlsDs" c_closeTls :: Ptr TlsDs -> IO ()
 
 
-foreign import ccall "fileDsSend" c_sendFile :: Ptr FileDs -> Ptr CChar -> CInt -> IO CInt
-foreign import ccall "sockDsSend" c_sendSock :: Ptr SockDs -> Ptr CChar -> CInt -> IO CInt
-foreign import ccall "tlsDsSend" c_sendTls :: Ptr TlsDs -> Ptr CChar -> CInt -> IO CInt
+foreign import ccall interruptible "fileDsSend" c_sendFile :: Ptr FileDs -> Ptr CChar -> CInt -> IO CInt
+foreign import ccall interruptible "sockDsSend" c_sendSock :: Ptr SockDs -> Ptr CChar -> CInt -> IO CInt
+foreign import ccall interruptible "tlsDsSend" c_sendTls :: Ptr TlsDs -> Ptr CChar -> CInt -> IO CInt
 
 
-foreign import ccall "fileDsRecv" c_recvFile :: Ptr FileDs -> Ptr CChar -> CInt -> IO CInt
-foreign import ccall "sockDsRecv" c_recvSock :: Ptr SockDs -> Ptr CChar -> CInt -> IO CInt
-foreign import ccall "tlsDsRecv" c_recvTls :: Ptr TlsDs -> Ptr CChar -> CInt -> IO CInt
+foreign import ccall interruptible "fileDsRecv" c_recvFile :: Ptr FileDs -> Ptr CChar -> CInt -> IO CInt
+foreign import ccall interruptible "sockDsRecv" c_recvSock :: Ptr SockDs -> Ptr CChar -> CInt -> IO CInt
+foreign import ccall interruptible "tlsDsRecv" c_recvTls :: Ptr TlsDs -> Ptr CChar -> CInt -> IO CInt

+ 42 - 0
test/Lazyness.hs

@@ -0,0 +1,42 @@
+{-# LANGUAGE OverloadedStrings #-}
+
+module Lazyness (tests) where
+
+import Distribution.TestSuite
+import Control.Concurrent(forkIO) 
+import qualified System.IO.Uniform as U
+import qualified System.IO.Uniform.Streamline as S
+import System.Timeout (timeout)  
+
+tests :: IO [Test]
+tests = return [Test readLine]
+  where
+    readLine = TestInstance
+      {run = testReadLine,
+       name = "Lazyness of readLine",
+       tags = [],
+       options = [],
+       setOption = \_ _ -> Right readLine
+      }
+      
+testReadLine :: IO Progress
+testReadLine = do
+  recv <- U.bindPort 8888
+  forkIO $ S.withClient (\_ _ -> do
+                            l <- S.receiveLine
+                            S.send l
+                            S.send "\n"
+                            return ()
+                        ) recv
+  r <- timeout 1000000 $ S.withServer (do
+                                     S.send "A test\n"
+                                     S.receiveLine
+                                     return ()
+                                 ) "127.0.0.1" 8888
+  case r of
+    Just _ -> return . Finished $ Pass
+    Nothing -> return . Finished . Fail $ "Timeout on Streamline.readLine"
+
+
+
+

+ 12 - 1
uniform-io.cabal

@@ -10,7 +10,7 @@ name:                uniform-io
 -- PVP summary:      +-+------- breaking API changes
 -- PVP summary:      +-+------- breaking API changes
 --                   | | +----- non-breaking API additions
 --                   | | +----- non-breaking API additions
 --                   | | | +--- code changes with no API change
 --                   | | | +--- code changes with no API change
-version:    0.1.0.0
+version:    0.1.1.0
 
 
 -- A short (one-line) description of the package.
 -- A short (one-line) description of the package.
 synopsis:   Uniform IO over files, network, watever.
 synopsis:   Uniform IO over files, network, watever.
@@ -112,3 +112,14 @@ library
   install-includes: ds.h
   install-includes: ds.h
   C-Sources: src/System/IO/Uniform/ds.c
   C-Sources: src/System/IO/Uniform/ds.c
   extra-libraries: ssl
   extra-libraries: ssl
+
+Test-suite lazyness
+  type: detailed-0.9
+  test-module: Lazyness
+  hs-source-dirs:
+    test
+  build-depends:
+    base >=4.7 && <5.0,
+    Cabal >= 1.9.2,
+    uniform-io == 0.1.1.0
+  ghc-options: -Wall -fno-warn-unused-do-bind -fwarn-incomplete-patterns -threaded