network-run 0.7.0 → 0.7.1
raw patch · 7 files changed
+53/−11 lines, 7 filesdep ~networkPVP: major bump suggested
API removals or changes: PVP suggests a major version bump
Dependency ranges changed: network
API changes (from Hackage documentation)
+ Network.Run.TCP: [settingsUnsafeClose] :: ServerSettings -> Bool
+ Network.Run.TCP.Timeout: [settingsUnsafeClose] :: ServerSettings -> Bool
+ Network.Run.UDP: [settingsUnsafeClose] :: ServerSettings -> Bool
- Network.Run.TCP: ServerSettings :: (Maybe SockAddr -> SomeException -> IO ()) -> Int -> Int -> (IO () -> IO ()) -> ServerSettings
+ Network.Run.TCP: ServerSettings :: (Maybe SockAddr -> SomeException -> IO ()) -> Int -> Bool -> Int -> (IO () -> IO ()) -> ServerSettings
- Network.Run.TCP.Timeout: ServerSettings :: (Maybe SockAddr -> SomeException -> IO ()) -> Int -> Int -> (IO () -> IO ()) -> ServerSettings
+ Network.Run.TCP.Timeout: ServerSettings :: (Maybe SockAddr -> SomeException -> IO ()) -> Int -> Bool -> Int -> (IO () -> IO ()) -> ServerSettings
- Network.Run.UDP: ServerSettings :: (Maybe SockAddr -> SomeException -> IO ()) -> Int -> Int -> (IO () -> IO ()) -> ServerSettings
+ Network.Run.UDP: ServerSettings :: (Maybe SockAddr -> SomeException -> IO ()) -> Int -> Bool -> Int -> (IO () -> IO ()) -> ServerSettings
Files
- CHANGELOG.md +11/−0
- Network/Run/Core.hs +15/−4
- Network/Run/TCP.hs +2/−2
- Network/Run/TCP/Timeout.hs +2/−2
- Network/Run/UDP.hs +1/−1
- network-run.cabal +2/−2
- test/TCPSpec.hs +20/−0
CHANGELOG.md view
@@ -1,5 +1,16 @@ # Revision history for network-run +## 0.7.1++* Sockets this library owns and has not handed to anyone are closed with+ `close(2)` rather than with `close`, which goes through the IO manager+ to tell a waiter that is not there.+* `settingsUnsafeClose` lets a server close its connections with+ `unsafeGracefulClose` or `unsafeClose`. The default keeps `close`,+ since only the caller knows whether its handler leaves a thread on the+ socket.+* Requires network 3.2.12.+ ## 0.7.0 * The accept loop is stopped by being told, through the new
Network/Run/Core.hs view
@@ -81,7 +81,7 @@ -- The options are set before 'connect'. openClientSocketWithOpts :: [(SocketOption, SockOptValue)] -> AddrInfo -> IO Socket-openClientSocketWithOpts opts addr = E.bracketOnError (openSocket addr) close $ \sock -> do+openClientSocketWithOpts opts addr = E.bracketOnError (openSocket addr) unsafeClose $ \sock -> do mapM_ (uncurry $ setSockOptValue sock) opts connect sock $ addrAddress addr return sock@@ -127,7 +127,7 @@ -- cannot be cleared. openServerSocketWithOpts :: [(SocketOption, SockOptValue)] -> AddrInfo -> IO Socket-openServerSocketWithOpts opts addr = E.bracketOnError (openSocket addr) close $ \sock -> do+openServerSocketWithOpts opts addr = E.bracketOnError (openSocket addr) unsafeClose $ \sock -> do setSocketOption sock ReuseAddr 1 #if !defined(openbsd_HOST_OS) when (addrFamily addr == AF_INET6) $ setSocketOption sock IPv6Only 1@@ -206,6 +206,12 @@ -- connection handler returns. Zero or less uses 'close' instead, -- which releases the file descriptor immediately. The default is -- 5000.+ , settingsUnsafeClose :: Bool+ -- ^ Closing a connected socket with 'unsafeGracefulClose' or+ -- 'unsafeClose', which skip the IO manager that 'close' goes through+ -- to tell a thread waiting on the socket. Set this only when the+ -- connection handler leaves no thread and no registered wait on the+ -- socket by the time it returns. The default is 'False'. , settingsAcceptRetryDelay :: Int -- ^ Microseconds to wait before retrying 'accept' after running -- out of file descriptors. The default is 100000.@@ -235,6 +241,7 @@ ServerSettings { settingsOnException = \_ _ -> return () , settingsGracefulCloseTimeout = 5000+ , settingsUnsafeClose = False , settingsAcceptRetryDelay = 100000 , settingsInstallShutdownHandler = const $ return () }@@ -253,8 +260,12 @@ -- | Closing a connected socket according to the settings. gcloseWith :: ServerSettings -> Socket -> IO () gcloseWith ServerSettings{..} sock- | settingsGracefulCloseTimeout <= 0 = close sock- | otherwise = gracefulClose sock settingsGracefulCloseTimeout+ | settingsGracefulCloseTimeout <= 0 = closer sock+ | otherwise = gracefulCloser sock settingsGracefulCloseTimeout+ where+ (closer, gracefulCloser)+ | settingsUnsafeClose = (unsafeClose, unsafeGracefulClose)+ | otherwise = (close, gracefulClose) ----------------------------------------------------------------
Network/Run/TCP.hs view
@@ -54,7 +54,7 @@ -> IO () runTCPServerWithSettings set mhost port server = do addr <- resolve Stream mhost port [AI_PASSIVE] NE.head- E.bracket (openTCPServerSocket addr) close $ \sock ->+ E.bracket (openTCPServerSocket addr) unsafeClose $ \sock -> runTCPServerWithSocketAndSettings set sock server -- | Running a TCP server on a given listen socket.@@ -83,7 +83,7 @@ -- is closed if anything goes wrong before the thread owning it has -- been forked. loop listener = do- more <- E.bracketOnError (acceptOrStop listener) (mapM_ (close . fst)) $ \maccepted ->+ more <- E.bracketOnError (acceptOrStop listener) (mapM_ (unsafeClose . fst)) $ \maccepted -> case maccepted of Nothing -> return False Just (conn, peer) -> do
Network/Run/TCP/Timeout.hs view
@@ -59,7 +59,7 @@ -> IO () runTCPServerWithSettings set tm mhost port server = do addr <- resolve Stream mhost port [AI_PASSIVE] NE.head- E.bracket (openTCPServerSocket addr) close $ \sock ->+ E.bracket (openTCPServerSocket addr) unsafeClose $ \sock -> runTCPServerWithSocketAndSettings set tm sock server -- | Running a TCP server on a given listen socket.@@ -90,7 +90,7 @@ -- is closed if anything goes wrong before the thread owning it has -- been forked. loop listener mgr = do- more <- E.bracketOnError (acceptOrStop listener) (mapM_ (close . fst)) $ \maccepted ->+ more <- E.bracketOnError (acceptOrStop listener) (mapM_ (unsafeClose . fst)) $ \maccepted -> case maccepted of Nothing -> return False Just (conn, peer) -> do
Network/Run/UDP.hs view
@@ -101,7 +101,7 @@ -- If 'connect' throws, the socket is closed here. On -- success it is owned by the new thread and is closed by -- its finalizer.- E.bracketOnError (openServerSocket addr) close $ \s -> do+ E.bracketOnError (openServerSocket addr) unsafeClose $ \s -> do connect s peeraddr forkDatagram set s peeraddr $ labelMe "UDP server" >> server s bs0
network-run.cabal view
@@ -1,6 +1,6 @@ cabal-version: 2.0 name: network-run-version: 0.7.0+version: 0.7.1 license: BSD3 license-file: LICENSE maintainer: kazu@iij.ad.jp@@ -31,7 +31,7 @@ build-depends: base >=4 && <5, bytestring >=0.10 && <0.13,- network >=3.2.10 && <3.3,+ network >=3.2.12 && <3.3, stm >=2.5 && <2.6, time-manager >=0.2 && <0.6
test/TCPSpec.hs view
@@ -150,6 +150,26 @@ putMVar gate () recv sock 1024 `shouldThrow` anyIOException + it "drains a connection with unsafeGracefulClose when asked to" $ limited $ do+ gate <- newEmptyMVar+ let set = defaultServerSettings{settingsGracefulCloseTimeout = 500, settingsUnsafeClose = True}+ withTCPServer set (\_ -> takeMVar gate) $ \port ->+ client port $ \sock -> do+ sendAll sock "hello"+ threadDelay 200000+ putMVar gate ()+ recv sock 1024 `shouldReturn` ""++ it "resets a connection with unsafeClose when asked to" $ limited $ do+ gate <- newEmptyMVar+ let set = defaultServerSettings{settingsGracefulCloseTimeout = 0, settingsUnsafeClose = True}+ withTCPServer set (\_ -> takeMVar gate) $ \port ->+ client port $ \sock -> do+ sendAll sock "hello"+ threadDelay 200000+ putMVar gate ()+ recv sock 1024 `shouldThrow` anyIOException+ it "serves many connections concurrently" $ limited $ withTCPServer defaultServerSettings echo $ \port -> do