Skip to content

Commit 9bbd9bc

Browse files
committed
Merge branch 'fix/try-multiple-addrinfo' of https://github.com/frasertweedale/HTTP
2 parents 06be24c + 5d132dc commit 9bbd9bc

File tree

1 file changed

+31
-8
lines changed

1 file changed

+31
-8
lines changed

Network/TCP.hs

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
{-# LANGUAGE ScopedTypeVariables #-}
12
{-# LANGUAGE TypeSynonymInstances #-}
23
-----------------------------------------------------------------------------
34
-- |
@@ -61,7 +62,7 @@ import Network.Socket ( socketToHandle )
6162
import Data.Char ( toLower )
6263
import Data.Word ( Word8 )
6364
import Control.Concurrent
64-
import Control.Exception ( onException )
65+
import Control.Exception ( IOException, bracketOnError, try )
6566
import Control.Monad ( liftM, when )
6667
import System.IO ( Handle, hFlush, IOMode(..), hClose )
6768
import System.IO.Error ( isEOFError )
@@ -236,15 +237,37 @@ openTCPConnection_ uri port stashInput = do
236237
-- like this as it just does a once-only installation of a shutdown handler to run at program exit,
237238
-- rather than actually shutting down after the action
238239
addrinfos <- withSocketsDo $ getAddrInfo (Just $ defaultHints { addrFamily = AF_UNSPEC, addrSocketType = Stream }) (Just fixedUri) (Just . show $ port)
240+
241+
let
242+
connectAddrInfo a = bracketOnError
243+
(socket (addrFamily a) Stream defaultProtocol) -- acquire
244+
Network.Socket.close -- release
245+
( \s -> do
246+
setSocketOption s KeepAlive 1
247+
connect s (addrAddress a)
248+
socketConnection_ fixedUri port s stashInput )
249+
250+
-- try multiple addresses; return Just connected socket or Nothing
251+
tryAddrInfos [] = return Nothing
252+
tryAddrInfos (h:t) =
253+
let next = \(_ :: IOException) -> tryAddrInfos t
254+
in try (connectAddrInfo h) >>= either next (return . Just)
255+
239256
case addrinfos of
240257
[] -> fail "openTCPConnection: getAddrInfo returned no address information"
241-
(a:_) -> do
242-
s <- socket (addrFamily a) Stream defaultProtocol
243-
onException (do
244-
setSocketOption s KeepAlive 1
245-
connect s (addrAddress a)
246-
socketConnection_ fixedUri port s stashInput
247-
) (Network.Socket.close s)
258+
259+
-- single AddrInfo; call connectAddrInfo directly so that specific
260+
-- exception is thrown in event of failure
261+
[ai] -> connectAddrInfo ai `catchIO` (\e -> fail $
262+
"openTCPConnection: failed to connect to "
263+
++ show (addrAddress ai) ++ ": " ++ show e)
264+
265+
-- multiple AddrInfos; try each until we get a connection, or run out
266+
ais ->
267+
let
268+
err = fail $ "openTCPConnection: failed to connect; tried addresses: "
269+
++ show (fmap addrAddress ais)
270+
in tryAddrInfos ais >>= maybe err return
248271

249272
-- | @socketConnection@, like @openConnection@ but using a pre-existing 'Socket'.
250273
socketConnection :: BufferType ty

0 commit comments

Comments
 (0)