
On Sat, 9 May 2020, Compl Yue wrote:
In top-level doc, the minimal example echo server uses Control.Exception.bracket like this:
E.bracket (open addr) close loop where resolve = do let hints = defaultHints { addrFlags = [AI_PASSIVE] , addrSocketType = Stream } head <$> getAddrInfo (Just hints) mhost (Just port) open addr = do sock <- socket (addrFamily addr) (addrSocketType addr) (addrProtocol addr) setSocketOption sock ReuseAddr 1 withFdSocket sock setCloseOnExecIfNeeded bind sock $ addrAddress addr listen sock 1024 return sock loop sock = forever $ do (conn, _peer) <- accept sock void $ forkFinally (server conn) (const $ gracefulClose conn 5000)
I happened to copy the configuration with another machine's IP address to run on my dev machine, then of course it failed binding to the IP, but in this case I suspect sock above is leaked without close, as open failed at all, so sock is not given to bracket for it to do the cleanup.
I think you are right. If 'bind' throws an exception then 'close' will not be called. You might move the block from 'setSocketOption' to 'listen' into 'loop' before 'forever'.