Skip to content
This repository was archived by the owner on Sep 20, 2023. It is now read-only.

Commit 27fc112

Browse files
committed
use sockets instead of handle in the code
1 parent 217c394 commit 27fc112

File tree

2 files changed

+48
-9
lines changed

2 files changed

+48
-9
lines changed

Network/Connection.hs

Lines changed: 47 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ module Network.Connection
2222

2323
-- * Exceptions
2424
, LineTooLong(..)
25+
, HostNotResolved(..)
26+
, HostCannotConnect(..)
2527

2628
-- * Library initialization
2729
, initConnectionContext
@@ -58,7 +60,8 @@ import System.X509 (getSystemCertificateStore)
5860

5961
import Network.Socks5
6062
import qualified Network as N
61-
import Network.Socket (Socket)
63+
import Network.Socket
64+
import Network.BSD (getProtocolNumber)
6265
import qualified Network.Socket as N (close)
6366
import qualified Network.Socket.ByteString as N
6467

@@ -81,7 +84,15 @@ type Manager = MVar (M.Map TLS.SessionID TLS.SessionData)
8184
-- the line in ConnectionGetLine.
8285
data LineTooLong = LineTooLong deriving (Show,Typeable)
8386

87+
-- | Exception raised when there's no resolution for a specific host
88+
data HostNotResolved = HostNotResolved String deriving (Show,Typeable)
89+
90+
-- | Exception raised when the connect failed
91+
data HostCannotConnect = HostCannotConnect String [E.IOException] deriving (Show,Typeable)
92+
8493
instance E.Exception LineTooLong
94+
instance E.Exception HostNotResolved
95+
instance E.Exception HostCannotConnect
8596

8697
connectionSessionManager :: Manager -> TLS.SessionManager
8798
connectionSessionManager mvar = TLS.SessionManager
@@ -159,22 +170,22 @@ connectTo :: ConnectionContext -- ^ The global context of this connection.
159170
connectTo cg cParams = do
160171
conFct <- getConFct (connectionUseSocks cParams)
161172
h <- conFct (connectionHostname cParams) (N.PortNumber $ connectionPort cParams)
162-
connectFromHandle cg h cParams
173+
connectFromSocket cg h cParams
163174
where
164-
getConFct Nothing = return N.connectTo
165-
getConFct (Just (OtherProxy h p)) = return $ \_ _ -> N.connectTo h (N.PortNumber p)
166-
getConFct (Just (SockSettingsSimple h p)) = return $ socksConnectTo h (N.PortNumber p)
175+
getConFct Nothing = return resolve'
176+
getConFct (Just (OtherProxy h p)) = return $ \_ _ -> resolve' h (N.PortNumber p)
177+
getConFct (Just (SockSettingsSimple h p)) = return $ socksConnectTo' h (N.PortNumber p)
167178
getConFct (Just (SockSettingsEnvironment v)) = do
168179
-- if we can't get the environment variable or that the variable cannot be parsed
169180
-- we connect directly.
170181
let name = maybe "SOCKS_SERVER" id v
171182
evar <- E.try (getEnv name)
172183
case evar of
173-
Left (_ :: E.IOException) -> return N.connectTo
184+
Left (_ :: E.IOException) -> return resolve'
174185
Right var ->
175186
case parseSocks var of
176-
Nothing -> return N.connectTo
177-
Just (sHost, sPort) -> return $ socksConnectTo sHost (N.PortNumber $ fromIntegral (sPort :: Int))
187+
Nothing -> return resolve'
188+
Just (sHost, sPort) -> return $ socksConnectTo' sHost (N.PortNumber $ fromIntegral (sPort :: Int))
178189

179190
-- Try to parse "host:port" or "host"
180191
parseSocks s =
@@ -186,6 +197,34 @@ connectTo cg cParams = do
186197
_ -> Nothing
187198
_ -> Nothing
188199

200+
resolve' host portid = do
201+
let serv = case portid of
202+
N.Service serv -> serv
203+
N.PortNumber n -> show n
204+
_ -> error "cannot resolve service"
205+
proto <- getProtocolNumber "tcp"
206+
let hints = defaultHints { addrFlags = [AI_ADDRCONFIG]
207+
, addrProtocol = proto
208+
, addrSocketType = Stream }
209+
addrs <- getAddrInfo (Just hints) (Just host) (Just serv)
210+
firstSuccessful $ map tryToConnect addrs
211+
where
212+
tryToConnect addr =
213+
E.bracketOnError
214+
(socket (addrFamily addr) (addrSocketType addr) (addrProtocol addr))
215+
(N.close)
216+
(\sock -> connect sock (addrAddress addr) >> return sock)
217+
firstSuccessful = go []
218+
where
219+
go :: [E.IOException] -> [IO a] -> IO a
220+
go [] [] = E.throwIO $ HostNotResolved host
221+
go l@(_:_) [] = E.throwIO $ HostCannotConnect host l
222+
go acc (act:followingActs) = do
223+
er <- E.try act
224+
case er of
225+
Left err -> go (err:acc) followingActs
226+
Right r -> return r
227+
189228
-- | Put a block of data in the connection.
190229
connectionPut :: Connection -> ByteString -> IO ()
191230
connectionPut connection content = withBackend doWrite connection

connection.cabal

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ Library
2929
, data-default-class
3030
, network >= 2.3
3131
, tls >= 1.3
32-
, socks >= 0.4
32+
, socks >= 0.5.5
3333
, x509 >= 1.5
3434
, x509-store >= 1.5
3535
, x509-system >= 1.5

0 commit comments

Comments
 (0)