connection 0.2.8 → 0.3.0
raw patch · 4 files changed
+81/−67 lines, 4 filesdep +basementdep −byteabledep ~basedep ~networkdep ~socksPVP ok
version bump matches the API change (PVP)
Dependencies added: basement
Dependencies removed: byteable
Dependency ranges changed: base, network, socks, tls
API changes (from Hackage documentation)
- Network.Connection: instance GHC.Exception.Exception Network.Connection.HostCannotConnect
- Network.Connection: instance GHC.Exception.Exception Network.Connection.HostNotResolved
- Network.Connection: instance GHC.Exception.Exception Network.Connection.LineTooLong
+ Network.Connection: connectionSessionManager :: Manager -> SessionManager
+ Network.Connection: instance GHC.Exception.Type.Exception Network.Connection.HostCannotConnect
+ Network.Connection: instance GHC.Exception.Type.Exception Network.Connection.HostNotResolved
+ Network.Connection: instance GHC.Exception.Type.Exception Network.Connection.LineTooLong
- Network.Connection: SockSettingsEnvironment :: (Maybe String) -> ProxySettings
+ Network.Connection: SockSettingsEnvironment :: Maybe String -> ProxySettings
Files
- LICENSE +1/−1
- Network/Connection.hs +70/−59
- Network/Connection/Types.hs +4/−1
- connection.cabal +6/−6
LICENSE view
@@ -1,4 +1,4 @@-Copyright (c) 2012 Vincent Hanquez <vincent@snarc.org>+Copyright (c) 2012-2019 Vincent Hanquez <vincent@snarc.org> All rights reserved.
Network/Connection.hs view
@@ -47,9 +47,9 @@ -- * TLS related operation , connectionSetSecure , connectionIsSecure+ , connectionSessionManager ) where -import Control.Applicative import Control.Concurrent.MVar import Control.Monad (join) import qualified Control.Exception as E@@ -60,11 +60,8 @@ import System.X509 (getSystemCertificateStore) -import Network.Socks5-import qualified Network as N+import Network.Socks5 (defaultSocksConf, socksConnectWithSocket, SocksAddress(..), SocksHostAddress(..)) import Network.Socket-import Network.BSD (getProtocolNumber)-import qualified Network.Socket as N (close) import qualified Network.Socket.ByteString as N import Data.Default.Class@@ -114,7 +111,7 @@ makeTLSParams :: ConnectionContext -> ConnectionID -> TLSSettings -> TLS.ClientParams makeTLSParams cg cid ts@(TLSSettingsSimple {}) = (TLS.defaultParamsClient (fst cid) portString)- { TLS.clientSupported = def { TLS.supportedCiphers = TLS.ciphersuite_all }+ { TLS.clientSupported = def { TLS.supportedCiphers = TLS.ciphersuite_default } , TLS.clientShared = def { TLS.sharedCAStore = globalCertificateStore cg , TLS.sharedValidationCache = validationCache@@ -171,63 +168,77 @@ -> ConnectionParams -- ^ The parameters for this connection (where to connect, and such). -> IO Connection -- ^ The new established connection on success. connectTo cg cParams = do- conFct <- getConFct (connectionUseSocks cParams)- let doConnect = conFct (connectionHostname cParams) (N.PortNumber $ connectionPort cParams)- E.bracketOnError doConnect N.close $ \h->+ let conFct = doConnect (connectionUseSocks cParams)+ (connectionHostname cParams)+ (connectionPort cParams)+ E.bracketOnError conFct (close . fst) $ \(h, _) -> connectFromSocket cg h cParams where- getConFct Nothing = return resolve'- getConFct (Just (OtherProxy h p)) = return $ \_ _ -> resolve' h (N.PortNumber p)- getConFct (Just (SockSettingsSimple h p)) = return $ socksConnectTo' h (N.PortNumber p)- getConFct (Just (SockSettingsEnvironment v)) = do- -- if we can't get the environment variable or that the variable cannot be parsed- -- we connect directly.- let name = maybe "SOCKS_SERVER" id v- evar <- E.try (getEnv name)- case evar of- Left (_ :: E.IOException) -> return resolve'- Right var ->- case parseSocks var of- Nothing -> return resolve'- Just (sHost, sPort) -> return $ socksConnectTo' sHost (N.PortNumber $ fromIntegral (sPort :: Int))+ sockConnect sockHost sockPort h p = do+ (sockServ, servAddr) <- resolve' sockHost sockPort+ let sockConf = defaultSocksConf servAddr+ let destAddr = SocksAddress (SocksAddrDomainName $ BC.pack h) p+ (dest, _) <- socksConnectWithSocket sockServ sockConf destAddr+ case dest of+ SocksAddrIPV4 h4 -> return (sockServ, SockAddrInet p h4)+ SocksAddrIPV6 h6 -> return (sockServ, SockAddrInet6 p 0 h6 0)+ SocksAddrDomainName _ -> error "internal error: socks connect return a resolved address as domain name" - -- Try to parse "host:port" or "host"- parseSocks s =- case break (== ':') s of- (sHost, "") -> Just (sHost, 1080)- (sHost, ':':portS) ->- case reads portS of- [(sPort,"")] -> Just (sHost, sPort)- _ -> Nothing- _ -> Nothing - resolve' host portid = do- let serv = case portid of- N.Service serv -> serv- N.PortNumber n -> show n- _ -> error "cannot resolve service" - proto <- getProtocolNumber "tcp"- let hints = defaultHints { addrFlags = [AI_ADDRCONFIG]- , addrProtocol = proto- , addrSocketType = Stream }- addrs <- getAddrInfo (Just hints) (Just host) (Just serv)- firstSuccessful $ map tryToConnect addrs+ doConnect proxy h p =+ case proxy of+ Nothing -> resolve' h p+ Just (OtherProxy proxyHost proxyPort) -> resolve' proxyHost proxyPort+ Just (SockSettingsSimple sockHost sockPort) ->+ sockConnect sockHost sockPort h p+ Just (SockSettingsEnvironment envName) -> do+ -- if we can't get the environment variable or that the string cannot be parsed+ -- we connect directly.+ let name = maybe "SOCKS_SERVER" id envName+ evar <- E.try (getEnv name)+ case evar of+ Left (_ :: E.IOException) -> resolve' h p+ Right var ->+ case parseSocks var of+ Nothing -> resolve' h p+ Just (sockHost, sockPort) -> sockConnect sockHost sockPort h p++ -- Try to parse "host:port" or "host"+ -- if port is ommited then the default SOCKS port (1080) is assumed+ parseSocks :: String -> Maybe (String, PortNumber)+ parseSocks s =+ case break (== ':') s of+ (sHost, "") -> Just (sHost, 1080)+ (sHost, ':':portS) ->+ case reads portS of+ [(sPort,"")] -> Just (sHost, sPort)+ _ -> Nothing+ _ -> Nothing++ -- Try to resolve the host/port into an address (zero to many of them), then+ -- try to connect from the first address to the last, returning the first one that+ -- succeed+ resolve' :: String -> PortNumber -> IO (Socket, SockAddr)+ resolve' host port = do+ let hints = defaultHints { addrFlags = [AI_ADDRCONFIG], addrSocketType = Stream }+ addrs <- getAddrInfo (Just hints) (Just host) (Just $ show port)+ firstSuccessful $ map tryToConnect addrs+ where+ tryToConnect addr =+ E.bracketOnError+ (socket (addrFamily addr) (addrSocketType addr) (addrProtocol addr))+ (close)+ (\sock -> connect sock (addrAddress addr) >> return (sock, addrAddress addr))+ firstSuccessful = go [] where- tryToConnect addr =- E.bracketOnError- (socket (addrFamily addr) (addrSocketType addr) (addrProtocol addr))- (N.close)- (\sock -> connect sock (addrAddress addr) >> return sock)- firstSuccessful = go []- where- go :: [E.IOException] -> [IO a] -> IO a- go [] [] = E.throwIO $ HostNotResolved host- go l@(_:_) [] = E.throwIO $ HostCannotConnect host l- go acc (act:followingActs) = do- er <- E.try act- case er of- Left err -> go (err:acc) followingActs- Right r -> return r+ go :: [E.IOException] -> [IO a] -> IO a+ go [] [] = E.throwIO $ HostNotResolved host+ go l@(_:_) [] = E.throwIO $ HostCannotConnect host l+ go acc (act:followingActs) = do+ er <- E.try act+ case er of+ Left err -> go (err:acc) followingActs+ Right r -> return r -- | Put a block of data in the connection. connectionPut :: Connection -> ByteString -> IO ()@@ -369,7 +380,7 @@ connectionClose :: Connection -> IO () connectionClose = withBackend backendClose where backendClose (ConnectionTLS ctx) = ignoreIOExc (TLS.bye ctx) `E.finally` TLS.contextClose ctx- backendClose (ConnectionSocket sock) = N.close sock+ backendClose (ConnectionSocket sock) = close sock backendClose (ConnectionStream h) = hClose h ignoreIOExc action = action `E.catch` \(_ :: E.IOException) -> return ()
Network/Connection/Types.hs view
@@ -16,7 +16,6 @@ import Data.X509.CertificateStore import Data.ByteString (ByteString) -import Network.BSD (HostName) import Network.Socket (PortNumber, Socket) import qualified Network.TLS as TLS @@ -26,6 +25,10 @@ data ConnectionBackend = ConnectionStream Handle | ConnectionSocket Socket | ConnectionTLS TLS.Context+++-- | Hostname This could either be a name string (punycode encoded) or an ipv4/ipv6+type HostName = String -- | Connection Parameters to establish a Connection. --
connection.cabal view
@@ -1,5 +1,5 @@ Name: connection-Version: 0.2.8+Version: 0.3.0 Description: Simple network library for all your connection need. .@@ -17,19 +17,19 @@ Category: Network stability: experimental Cabal-Version: >=1.6-Homepage: http://github.com/vincenthz/hs-connection+Homepage: https://github.com/vincenthz/hs-connection extra-source-files: README.md CHANGELOG.md Library Build-Depends: base >= 3 && < 5+ , basement , bytestring- , byteable , containers , data-default-class- , network >= 2.3- , tls >= 1.3- , socks >= 0.5.5+ , network >= 2.6+ , tls >= 1.4+ , socks >= 0.6 , x509 >= 1.5 , x509-store >= 1.5 , x509-system >= 1.5