This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "snap-server".

The branch, master has been updated
       via  6737c7d5102c573296a1ca7a8b2560e6e081f259 (commit)
       via  fdeb9def160fb610aa7723b5c3788ef7c58a1aeb (commit)
       via  2e5888136d04168b02d4d4ad3a168300e61727d7 (commit)
      from  9b077119d681c625c1af61993a58da57f7eff69f (commit)


Summary of changes:
 snap-server.cabal                              |   12 +++++--
 src/Snap/Internal/Http/Server.hs               |   45 +++++++++++++----------
 src/Snap/Internal/Http/Server/LibevBackend.hs  |   31 ++++++++++------
 src/Snap/Internal/Http/Server/SimpleBackend.hs |   31 ++++++++++++----
 src/System/SendFile.hs                         |   30 ++++++++++++++++
 src/System/SendFile/Darwin.hsc                 |   40 +++++++++++++++++++++
 src/System/SendFile/FreeBSD.hsc                |   37 +++++++++++++++++++
 src/System/SendFile/Linux.hsc                  |   41 +++++++++++++++++++++
 8 files changed, 224 insertions(+), 43 deletions(-)
 create mode 100644 src/System/SendFile.hs
 create mode 100644 src/System/SendFile/Darwin.hsc
 create mode 100644 src/System/SendFile/FreeBSD.hsc
 create mode 100644 src/System/SendFile/Linux.hsc

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 6737c7d5102c573296a1ca7a8b2560e6e081f259
Merge: fdeb9de 9b07711
Author: Shu-yu Guo <[email protected]>
Date:   Sun Jun 6 17:40:43 2010 -0700

    Merge branch 'master' of git.snapframework.com:snap-server
    
    Conflicts:
        src/Snap/Internal/Http/Server/SimpleBackend.hs

diff --cc src/Snap/Internal/Http/Server/SimpleBackend.hs
index bc074c0,03a138c..657c946
--- a/src/Snap/Internal/Http/Server/SimpleBackend.hs
+++ b/src/Snap/Internal/Http/Server/SimpleBackend.hs
@@@ -149,7 -135,7 +149,7 @@@ timeoutThread backend = loo
          -- atomic swap edit list
          now   <- getCurrentDateTime
          edits <- atomicModifyIORef tedits $ \t -> (D.empty, D.toList t)
--        
++
          let table' = foldl' (flip ($)) table edits
          !t'   <- killOlderThan now table'
          return t'
commit fdeb9def160fb610aa7723b5c3788ef7c58a1aeb
Author: Shu-yu Guo <[email protected]>
Date:   Sun Jun 6 17:39:22 2010 -0700

    Add our own sendfile

diff --git a/snap-server.cabal b/snap-server.cabal
index d102e1d..0bf847d 100644
--- a/snap-server.cabal
+++ b/snap-server.cabal
@@ -93,6 +93,7 @@ Library
     Snap.Internal.Http.Parser,
     Snap.Internal.Http.Server,  
     Snap.Internal.Http.Server.Date
+    System.SendFile
 
   build-depends:
     array >= 0.2 && <0.4,
@@ -111,7 +112,6 @@ Library
     monads-fd,
     network == 2.2.1.*,
     old-locale,
-    sendfile >= 0.6.1 && < 0.7,
     snap-core >= 0.2.7 && <0.3,
     time,
     transformers,
@@ -134,10 +134,16 @@ Library
     other-modules: Snap.Internal.Http.Server.SimpleBackend
 
   if os(linux)
-    cpp-options: -DLINUX
+    cpp-options: -DLINUX -DHAS_SENDFILE
+    other-modules: System.SendFile.Linux
 
   if os(darwin)
-    cpp-options: -DOSX
+    cpp-options: -DOSX -DHAS_SENDFILE
+    other-modules: System.SendFile.Darwin
+
+  if os(freebsd)
+    cpp-options: -DFREEBSD -DHAS_SENDFILE
+    other-modules: System.SendFile.FreeBSD
 
   ghc-prof-options: -prof -auto-all
 
diff --git a/src/Snap/Internal/Http/Server.hs b/src/Snap/Internal/Http/Server.hs
index 6388395..03f233f 100644
--- a/src/Snap/Internal/Http/Server.hs
+++ b/src/Snap/Internal/Http/Server.hs
@@ -243,18 +243,18 @@ logA' logger req rsp = do
 
 
 ------------------------------------------------------------------------------
-runHTTP :: ByteString           -- ^ local host name
-        -> ByteString           -- ^ local ip address
-        -> Int                  -- ^ local port
-        -> ByteString           -- ^ remote ip address
-        -> Int                  -- ^ remote port
-        -> Maybe Logger         -- ^ access logger
-        -> Maybe Logger         -- ^ error logger
-        -> Enumerator IO ()     -- ^ read end of socket
-        -> Iteratee IO ()       -- ^ write end of socket
-        -> (FilePath -> IO ())  -- ^ sendfile end
-        -> IO ()                -- ^ timeout tickler
-        -> ServerHandler        -- ^ handler procedure
+runHTTP :: ByteString                  -- ^ local host name
+        -> ByteString                  -- ^ local ip address
+        -> Int                         -- ^ local port
+        -> ByteString                  -- ^ remote ip address
+        -> Int                         -- ^ remote port
+        -> Maybe Logger                -- ^ access logger
+        -> Maybe Logger                -- ^ error logger
+        -> Enumerator IO ()            -- ^ read end of socket
+        -> Iteratee IO ()              -- ^ write end of socket
+        -> (FilePath -> Int -> IO ())  -- ^ sendfile end
+        -> IO ()                       -- ^ timeout tickler
+        -> ServerHandler               -- ^ handler procedure
         -> IO ()
 runHTTP lh lip lp rip rp alog elog
         readEnd writeEnd onSendFile tickle handler =
@@ -294,11 +294,11 @@ logError s = gets _logError >>= (\l -> liftIO $ l s)
 
 ------------------------------------------------------------------------------
 -- | Runs an HTTP session.
-httpSession :: Iteratee IO ()       -- ^ write end of socket
-            -> ForeignPtr CChar     -- ^ iteratee buffer
-            -> (FilePath -> IO ())  -- ^ sendfile continuation
-            -> IO ()                -- ^ timeout tickler
-            -> ServerHandler        -- ^ handler procedure
+httpSession :: Iteratee IO ()              -- ^ write end of socket
+            -> ForeignPtr CChar            -- ^ iteratee buffer
+            -> (FilePath -> Int -> IO ())  -- ^ sendfile continuation
+            -> IO ()                       -- ^ timeout tickler
+            -> ServerHandler               -- ^ handler procedure
             -> ServerMonad ()
 httpSession writeEnd' ibuf onSendFile tickle handler = do
 
@@ -510,15 +510,20 @@ sendResponse :: Response
              -> Iteratee IO a
              -> ForeignPtr CChar
              -> IO ()
-             -> (FilePath -> IO a)
-             -> ServerMonad (Int,a)
+             -> (FilePath -> Int -> IO a)
+             -> ServerMonad (Int, a)
 sendResponse rsp' writeEnd ibuf killBuffering onSendFile = do
     rsp <- fixupResponse rsp'
     let !headerString = mkHeaderString rsp
 
     (!x,!bs) <- case (rspBody rsp) of
                   (Enum e)     -> liftIO $ whenEnum headerString e
+#if defined(HAS_SENDFILE)
                   (SendFile f) -> liftIO $ whenSendFile headerString rsp f
+#else
+                  (SendFile f) -> liftIO $ whenEnum headerString
+                                                    (I.enumFile f)
+#endif
 
     return $! (bs,x)
 
@@ -536,7 +541,7 @@ sendResponse rsp' writeEnd ibuf killBuffering onSendFile = 
do
         enumBS hs writeEnd >>= run
 
         let !cl = fromJust $ rspContentLength r
-        x <- onSendFile f
+        x <- onSendFile f cl
         return (x, cl)
 
     (major,minor) = rspHttpVersion rsp'
diff --git a/src/Snap/Internal/Http/Server/LibevBackend.hs 
b/src/Snap/Internal/Http/Server/LibevBackend.hs
index 915d9be..f3ba2bb 100644
--- a/src/Snap/Internal/Http/Server/LibevBackend.hs
+++ b/src/Snap/Internal/Http/Server/LibevBackend.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE CPP #-}
 {-# LANGUAGE BangPatterns #-}
 {-# LANGUAGE DeriveDataTypeable #-}
 {-# LANGUAGE ForeignFunctionInterface #-}
@@ -54,13 +55,17 @@ import           Foreign.C.Types
 import           GHC.Conc (forkOnIO)
 import           Network.Libev
 import           Network.Socket
-import qualified Network.Socket.SendFile as SF
 import           Prelude hiding (catch)
 import           System.Timeout
 ------------------------------------------------------------------------------
 import           Snap.Iteratee
 import           Snap.Internal.Debug
 
+#if defined(HAS_SENDFILE) && !defined(PORTABLE)
+import qualified System.SendFile as SF
+import           System.Posix.IO
+import           System.Posix.Types (Fd(..))
+#endif
 
 data Backend = Backend
     { _acceptSocket      :: !Socket
@@ -110,22 +115,16 @@ name :: ByteString
 name = "libev"
 
 
-sendFile :: Connection -> FilePath -> IO ()
-sendFile c fp = do
+sendFile :: Connection -> FilePath -> Int -> IO ()
+sendFile c fp total = do
     withMVar lock $ \_ -> do
       act <- readIORef $ _writeActive c
       when act $ evIoStop loop io
       writeIORef (_writeActive c) False
       evAsyncSend loop asy
-      evTimerStop loop (_timerObj c)
 
-    -- FIXME
-    -- Temporary hack to stop sendFile from timing out.
-    -- An actual fix requires us to write our own sendfile wrapper that
-    -- checks for EINTR (will libev timers raise EINTR on sendfile?)
-    -- on OS X and just the return value on Linux to tickle the timeout.
-    SF.sendFile s fp
-    tickleTimeout c
+    fd <- openFd fp ReadOnly Nothing defaultFileFlags
+    go fd 0 total
 
     withMVar lock $ \_ -> do
       tryTakeMVar $ _readAvailable c
@@ -133,7 +132,15 @@ sendFile c fp = do
       evAsyncSend loop asy
 
   where
-    s    = _socket c
+    go fd off bytes
+      | bytes == 0 = return ()
+      | otherwise  = do
+            sent <- SF.sendFile sfd fd off bytes
+            if sent < bytes
+              then tickleTimeout c >> go fd (off+sent) (bytes-sent)
+              else return ()
+
+    sfd  = Fd $ _socketFd c
     io   = _connWriteIOObj c
     b    = _backend c
     loop = _evLoop b
diff --git a/src/Snap/Internal/Http/Server/SimpleBackend.hs 
b/src/Snap/Internal/Http/Server/SimpleBackend.hs
index 9ba4665..bc074c0 100644
--- a/src/Snap/Internal/Http/Server/SimpleBackend.hs
+++ b/src/Snap/Internal/Http/Server/SimpleBackend.hs
@@ -1,4 +1,5 @@
 {-# LANGUAGE BangPatterns #-}
+{-# LANGUAGE CPP #-}
 {-# LANGUAGE DeriveDataTypeable #-}
 {-# LANGUAGE ForeignFunctionInterface #-}
 {-# LANGUAGE OverloadedStrings #-}
@@ -48,13 +49,18 @@ import           Foreign.C.Types (CTime)
 import           GHC.Conc (labelThread, forkOnIO)
 import           Network.Socket
 import qualified Network.Socket.ByteString as SB
-import qualified Network.Socket.SendFile as SF
 import           Prelude hiding (catch)
 ------------------------------------------------------------------------------
 import           Snap.Internal.Debug
 import           Snap.Internal.Http.Server.Date
 import           Snap.Iteratee hiding (foldl')
 
+#if defined(HAS_SENDFILE) && !defined(PORTABLE)
+import qualified System.SendFile as SF
+import           System.Posix.IO
+import           System.Posix.Types (Fd(..))
+#endif
+
 
 data BackendTerminatedException = BackendTerminatedException
    deriving (Typeable)
@@ -85,10 +91,20 @@ name :: ByteString
 name = "simple"
 
 
-sendFile :: Connection -> FilePath -> IO ()
-sendFile c fp = do
-    let s = _socket c
-    SF.sendFile s fp
+sendFile :: Connection -> FilePath -> Int -> IO ()
+sendFile c fp sz = do
+    fd <- openFd fp ReadOnly Nothing defaultFileFlags
+    go fd 0 sz
+  where
+    go fd off bytes
+      | bytes == 0 = return ()
+      | otherwise  = do
+            sent <- SF.sendFile sfd fd off bytes
+            if sent < bytes
+              then tickleTimeout c >> go fd (off+sent) (bytes-sent)
+              else return ()
+
+    sfd = Fd . fdSocket $ _socket c
 
 
 bindIt :: ByteString         -- ^ bind address, or \"*\" for all
@@ -278,6 +294,7 @@ instance Exception TimeoutException
 
 tickleTimeout :: Connection -> IO ()
 tickleTimeout conn = do
+    debug "Backend.tickleTimeout"
     now <- getCurrentDateTime
     tid <- readMVar $ _connTid conn
 
diff --git a/src/System/SendFile.hs b/src/System/SendFile.hs
index 9a2de65..2810232 100644
--- a/src/System/SendFile.hs
+++ b/src/System/SendFile.hs
@@ -1,7 +1,7 @@
 {-# LANGUAGE CPP #-}
 
 -- | Snap's unified interface to sendfile.
--- Modified from sendfile by Matthew Elder
+-- Modified from sendfile 0.6.1
 
 module System.SendFile
   ( sendFile
commit 2e5888136d04168b02d4d4ad3a168300e61727d7
Author: Shu-yu Guo <[email protected]>
Date:   Sun Jun 6 17:36:22 2010 -0700

    Add our own sendfile wrappers so we can do timeout

diff --git a/src/System/SendFile.hs b/src/System/SendFile.hs
new file mode 100644
index 0000000..9a2de65
--- /dev/null
+++ b/src/System/SendFile.hs
@@ -0,0 +1,30 @@
+{-# LANGUAGE CPP #-}
+
+-- | Snap's unified interface to sendfile.
+-- Modified from sendfile by Matthew Elder
+
+module System.SendFile
+  ( sendFile
+  , sendFileMode
+  ) where
+
+#if defined(LINUX)
+import System.SendFile.Linux (sendFile)
+
+sendFileMode :: String
+sendFileMode = "LINUX_SENDFILE"
+#endif
+
+#if defined(FREEBSD)
+import System.SendFile.FreeBSD (sendFile)
+
+sendFileMode :: String
+sendFileMode = "FREEBSD_SENDFILE"
+#endif
+
+#if defined(OSX)
+import System.SendFile.Darwin (sendFile)
+
+sendFileMode :: String
+sendFileMode = "DARWIN_SENDFILE"
+#endif
diff --git a/src/System/SendFile/Darwin.hsc b/src/System/SendFile/Darwin.hsc
new file mode 100644
index 0000000..9a8d98a
--- /dev/null
+++ b/src/System/SendFile/Darwin.hsc
@@ -0,0 +1,40 @@
+{-# LANGUAGE ForeignFunctionInterface #-}
+-- | Darwin system-dependent code for 'sendfile'.
+module System.SendFile.Darwin (sendFile) where
+
+import Foreign.C.Error (eAGAIN, eINTR, getErrno, throwErrno)
+import Foreign.C.Types (CInt)
+import Foreign.Marshal (alloca)
+import Foreign.Ptr (Ptr, nullPtr)
+import Foreign.Storable (peek, poke)
+import System.Posix.Types (Fd, COff)
+
+sendFile :: Fd -> Fd -> Int -> Int -> IO Int
+sendFile out_fd in_fd off count
+  | count == 0 = return 0
+  | otherwise  = alloca $ \pbytes -> do
+        poke pbytes $ min maxBytes (fromIntegral count)
+        sbytes <- sendfile out_fd in_fd (fromIntegral off) pbytes
+        return $ fromEnum sbytes
+
+sendfile :: Fd -> Fd -> COff -> Ptr COff -> IO COff
+sendfile out_fd in_fd off pbytes = do
+    status <- c_sendfile out_fd in_fd off pbytes
+    nsent <- peek pbytes
+    if status == 0
+      then return nsent
+      else do errno <- getErrno
+              if (errno == eAGAIN) || (errno == eINTR)
+                then return nsent
+                else throwErrno "System.SendFile.Darwin"
+
+-- max num of bytes in one send
+maxBytes :: COff
+maxBytes = maxBound :: COff
+
+-- in Darwin sendfile gives LFS support (no sendfile64 routine)
+foreign import ccall unsafe "sys/uio.h sendfile" c_sendfile_darwin
+    :: Fd -> Fd -> COff -> Ptr COff -> Ptr () -> CInt -> IO CInt
+
+c_sendfile :: Fd -> Fd -> COff -> Ptr COff -> IO CInt
+c_sendfile out_fd in_fd off pbytes = c_sendfile_darwin in_fd out_fd off pbytes 
nullPtr 0
diff --git a/src/System/SendFile/FreeBSD.hsc b/src/System/SendFile/FreeBSD.hsc
new file mode 100644
index 0000000..9be08dc
--- /dev/null
+++ b/src/System/SendFile/FreeBSD.hsc
@@ -0,0 +1,37 @@
+{-# LANGUAGE ForeignFunctionInterface #-}
+-- | FreeBSD system-dependent code for 'sendfile'.
+module System.SendFile.FreeBSD (sendFile) where
+
+import Foreign.C.Error (eAGAIN, eINTR, getErrno, throwErrno)
+import Foreign.C.Types (CInt, CSize)
+import Foreign.Marshal.Alloc (alloca)
+import Foreign.Ptr (Ptr, nullPtr)
+import Foreign.Storable (peek)
+import System.Posix.Types (COff, Fd)
+
+sendFile :: Fd -> Fd -> Int -> Int -> IO Int
+sendFile out_fd in_fd off count
+  | count == 0 = return 0
+  | otherwise  = alloca $ \pbytes -> do
+        sbytes <- sendfile out_fd in_fd (fromIntegral off)
+                                        (fromIntegral count) pbytes
+        return $ fromEnum sbytes
+
+sendfile :: Fd -> Fd -> COff -> CSize -> Ptr COff -> IO COff
+sendfile out_fd in_fd off count pbytes =
+    do threadWaitWrite out_fd
+       res <- c_sendfile_freebsd in_fd out_fd off count nullPtr pbytes 0
+       nsent <- peek pbytes
+       if (res == 0)
+          then return nsent
+          else do errno <- getErrno
+                  if (errno == eAGAIN) || (errno == eINTR)
+                   then return nsent
+                   else throwErrno "System.SendFile.FreeBSD.sendfile"
+
+-- max num of bytes in one send
+maxBytes :: CSize
+maxBytes = maxBound :: CSize
+
+foreign import ccall unsafe "sys/uio.h sendfile" c_sendfile_freebsd
+    :: Fd -> Fd -> COff -> CSize -> Ptr () -> Ptr COff -> CInt -> IO CInt
diff --git a/src/System/SendFile/Linux.hsc b/src/System/SendFile/Linux.hsc
new file mode 100644
index 0000000..97962c2
--- /dev/null
+++ b/src/System/SendFile/Linux.hsc
@@ -0,0 +1,41 @@
+{-# LANGUAGE ForeignFunctionInterface #-}
+-- | Linux system-dependent code for 'sendfile'.
+module System.SendFile.Linux (sendFile) where
+
+import Foreign.C.Error (eAGAIN, getErrno, throwErrno)
+import Foreign.C.Types (CSize)
+import Foreign.Marshal (alloca)
+import Foreign.Ptr (Ptr, nullPtr)
+import Foreign.Storable (poke)
+import System.Posix.Types (Fd, COff, CSsize)
+
+sendFile :: Fd -> Fd -> Int -> Int -> IO Int
+sendFile out_fd in_fd off count
+  | count == 0 = return 0
+  | off == 0   = do
+        sbytes <- sendfile out_fd in_fd nullPtr bytes
+        return $ fromEnum sbytes
+  | otherwise  = alloca $ \poff -> do
+        poke poff (fromIntegral off)
+        sbytes <- sendfile out_fd in_fd poff bytes
+        return $ fromEnum sbytes
+    where
+      bytes = min (fromIntegral count) maxBytes
+
+sendfile :: Fd -> Fd -> Ptr COff -> CSize -> IO CSsize
+sendfile out_fd in_fd poff bytes = do
+    nsent <- c_sendfile out_fd in_fd poff bytes
+    if nsent <= -1
+      then do errno <- getErrno
+              if errno == eAGAIN
+                then sendfile out_fd in_fd poff bytes
+                else throwErrno "System.SendFile.Linux"
+      else return nsent
+
+-- max num of bytes in one send
+maxBytes :: CSize
+maxBytes = maxBound :: CSize
+
+-- sendfile64 gives LFS support
+foreign import ccall unsafe "sys/sendfile.h sendfile64" c_sendfile
+    :: Fd -> Fd -> Ptr COff -> CSize -> IO CSsize
-----------------------------------------------------------------------


hooks/post-receive
-- 
snap-server
_______________________________________________
Snap mailing list
[email protected]
http://mailman-mail5.webfaction.com/listinfo/snap

Reply via email to