@@ -64,7 +64,7 @@ module Network.Wai.Handler.Warp
6464#endif
6565 ) where
6666
67−import Prelude hiding (lines)
67+import Prelude hiding (lines, catch)
6868import Network.Wai
6969
7070import Data.ByteString (ByteString)
@@ -76,9 +76,9 @@ import Network (sClose, Socket)
7676import Network.Socket (accept, SockAddr)
7777import qualified Network.Socket.ByteString as Sock
7878import Control.Exception
79− ( mask, handle, onException, bracket
80− , Exception, SomeException
81− , fromException, AsyncException (ThreadKilled)
79+ ( mask, catch, handle, onException, bracket
80+ , Exception, SomeException, IOException, AsyncException (ThreadKilled)
81+ , fromException, toException
8282 , try
8383#if __GLASGOW_HASKELL__ >= 702
8484 , allowInterrupt
@@ -89,7 +89,7 @@ import Control.Exception
8989 , finally
9090#endif
9191 )
92−import Control.Concurrent (forkIO)
92+import Control.Concurrent (forkIO, threadDelay)
9393import Data.Maybe (fromMaybe, isJust)
9494import Data.Char (toLower, isHexDigit)
9595import Data.Word (Word)
@@ -127,7 +127,6 @@ import qualified Data.IORef as I
127127import Data.Conduit.Network (bindPort, HostPreference (HostIPv4))
128128
129129#if WINDOWS
130−import Control.Concurrent (threadDelay)
131130import qualified Control.Concurrent.MVar as MV
132131import Network.Socket (withSocketsDo)
133132#endif
@@ -221,21 +220,29 @@ runSettingsSocket set socket app =
221220
222221runSettingsConnection :: Settings -> IO (Connection, SockAddr) -> Application -> IO ()
223222runSettingsConnection set getConn app = do
224− let onE = settingsOnException set
225− port = settingsPort set
226− onOpen = settingsOnOpen set
227− onClose = settingsOnClose set
228223 tm <- maybe (T.initialize $ settingsTimeout set * 1000000) return
229224 $ settingsManager set
230225 mask $ \restore -> forever $ do
231226 allowInterrupt
232− (conn, addr) <- getConn
227+ (conn, addr) <- getConnLoop
233228 void $ forkIO $ do
234229 th <- T.registerKillThread tm
235230 handle onE $ (do onOpen
236231 restore $ serveConnection set th port app conn addr
237232 connClose conn >> T.cancel th >> onClose
238233 ) `onException` (T.cancel th >> connClose conn >> onClose)
234+ where
235+ -- FIXME: only IOEception is caught. What about other exceptions?
236+ getConnLoop = getConn `catch` \(e :: IOException) -> do
237+ onE (toException e)
238+ -- "resource exhausted (Too many open files)" may happen by accept().
239+ -- Wait a second hoping that resource will be available.
240+ threadDelay 1000000
241+ getConnLoop
242+ onE = settingsOnException set
243+ port = settingsPort set
244+ onOpen = settingsOnOpen set
245+ onClose = settingsOnClose set
239246
240247-- | Contains a @Source@ and a byte count that is still to be read in.
241248newtype IsolatedBSSource = IsolatedBSSource (I.IORef (Int, ResumableSource (ResourceT IO) ByteString))