packages feed

connection 0.2.5 → 0.2.6

raw patch · 3 files changed

+92/−12 lines, 3 filesdep ~socksdep ~tlsPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependency ranges changed: socks, tls

API changes (from Hackage documentation)

- Network.Connection: connectionHostname :: ConnectionParams -> HostName
- Network.Connection: connectionPort :: ConnectionParams -> PortNumber
- Network.Connection: connectionUseSecure :: ConnectionParams -> Maybe TLSSettings
- Network.Connection: connectionUseSocks :: ConnectionParams -> Maybe ProxySettings
- Network.Connection: instance Exception LineTooLong
- Network.Connection: instance Show LineTooLong
- Network.Connection: instance Typeable LineTooLong
- Network.Connection: settingDisableCertificateValidation :: TLSSettings -> Bool
- Network.Connection: settingDisableSession :: TLSSettings -> Bool
- Network.Connection: settingUseServerName :: TLSSettings -> Bool
+ Network.Connection: HostCannotConnect :: String -> [IOException] -> HostCannotConnect
+ Network.Connection: HostNotResolved :: String -> HostNotResolved
+ Network.Connection: [connectionHostname] :: ConnectionParams -> HostName
+ Network.Connection: [connectionPort] :: ConnectionParams -> PortNumber
+ Network.Connection: [connectionUseSecure] :: ConnectionParams -> Maybe TLSSettings
+ Network.Connection: [connectionUseSocks] :: ConnectionParams -> Maybe ProxySettings
+ Network.Connection: [settingDisableCertificateValidation] :: TLSSettings -> Bool
+ Network.Connection: [settingDisableSession] :: TLSSettings -> Bool
+ Network.Connection: [settingUseServerName] :: TLSSettings -> Bool
+ Network.Connection: connectFromSocket :: ConnectionContext -> Socket -> ConnectionParams -> IO Connection
+ Network.Connection: connectionGetExact :: Connection -> Int -> IO ByteString
+ Network.Connection: data HostCannotConnect
+ Network.Connection: data HostNotResolved
+ 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: instance GHC.Show.Show Network.Connection.HostCannotConnect
+ Network.Connection: instance GHC.Show.Show Network.Connection.HostNotResolved
+ Network.Connection: instance GHC.Show.Show Network.Connection.LineTooLong

Files

Network/Connection.hs view
@@ -22,6 +22,8 @@      -- * Exceptions     , LineTooLong(..)+    , HostNotResolved(..)+    , HostCannotConnect(..)      -- * Library initialization     , initConnectionContext@@ -29,11 +31,13 @@      -- * Connection operation     , connectFromHandle+    , connectFromSocket     , connectTo     , connectionClose      -- * Sending and receiving data     , connectionGet+    , connectionGetExact     , connectionGetChunk     , connectionGetChunk'     , connectionGetLine@@ -57,6 +61,10 @@  import Network.Socks5 import qualified Network as N+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 import Data.Data@@ -77,7 +85,15 @@ -- the line in ConnectionGetLine. data LineTooLong = LineTooLong deriving (Show,Typeable) +-- | Exception raised when there's no resolution for a specific host+data HostNotResolved = HostNotResolved String deriving (Show,Typeable)++-- | Exception raised when the connect failed+data HostCannotConnect = HostCannotConnect String [E.IOException] deriving (Show,Typeable)+ instance E.Exception LineTooLong+instance E.Exception HostNotResolved+instance E.Exception HostCannotConnect  connectionSessionManager :: Manager -> TLS.SessionManager connectionSessionManager mvar = TLS.SessionManager@@ -135,6 +151,19 @@           withSecurity (Just tlsSettings) = tlsEstablish h (makeTLSParams cg cid tlsSettings) >>= connectionNew cid . ConnectionTLS           cid = (connectionHostname p, connectionPort p) +-- | Use an already established handle to create a connection object.+--+-- if the TLS Settings is set, it will do the handshake with the server.+-- The SOCKS settings have no impact here, as the handle is already established+connectFromSocket :: ConnectionContext+                  -> Socket+                  -> ConnectionParams+                  -> IO Connection+connectFromSocket cg sock p = withSecurity (connectionUseSecure p)+    where withSecurity Nothing            = connectionNew cid $ ConnectionSocket sock+          withSecurity (Just tlsSettings) = tlsEstablish sock (makeTLSParams cg cid tlsSettings) >>= connectionNew cid . ConnectionTLS+          cid = (connectionHostname p, connectionPort p)+ -- | connect to a destination using the parameter connectTo :: ConnectionContext -- ^ The global context of this connection.           -> ConnectionParams  -- ^ The parameters for this connection (where to connect, and such).@@ -142,22 +171,22 @@ connectTo cg cParams = do     conFct <- getConFct (connectionUseSocks cParams)     h      <- conFct (connectionHostname cParams) (N.PortNumber $ connectionPort cParams)-    connectFromHandle cg h cParams+    connectFromSocket cg h cParams   where-        getConFct Nothing                            = return N.connectTo-        getConFct (Just (OtherProxy h p))            = return $ \_ _ -> N.connectTo h (N.PortNumber p)-        getConFct (Just (SockSettingsSimple h p))    = return $ socksConnectTo h (N.PortNumber p)+        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 N.connectTo+                Left (_ :: E.IOException) -> return resolve'                 Right var                 ->                     case parseSocks var of-                        Nothing             -> return N.connectTo-                        Just (sHost, sPort) -> return $ socksConnectTo sHost (N.PortNumber $ fromIntegral (sPort :: Int))+                        Nothing             -> return resolve'+                        Just (sHost, sPort) -> return $ socksConnectTo' sHost (N.PortNumber $ fromIntegral (sPort :: Int))          -- Try to parse "host:port" or "host"         parseSocks s =@@ -169,12 +198,57 @@                         _            -> 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+          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+ -- | Put a block of data in the connection. connectionPut :: Connection -> ByteString -> IO () connectionPut connection content = withBackend doWrite connection     where doWrite (ConnectionStream h) = B.hPut h content >> hFlush h+          doWrite (ConnectionSocket s) = N.sendAll s content           doWrite (ConnectionTLS ctx)  = TLS.sendData ctx $ L.fromChunks [content] +-- | Get exact count of bytes from a connection.+--+-- The size argument is the exact amount that must be returned to the user.+-- The call will wait until all data is available.  Hence, it behaves like+-- 'B.hGet'.+--+-- On end of input, 'connectionGetExact' will throw an 'E.isEOFError'+-- exception.+connectionGetExact :: Connection -> Int -> IO ByteString+connectionGetExact conn x = loop B.empty 0+  where loop bs y+          | y == x = return bs+          | otherwise = do+            next <- connectionGet conn (x - y)+            loop (B.append bs next) (y + (B.length next))+ -- | Get some bytes from a connection. -- -- The size argument is just the maximum that could be returned to the user.@@ -214,6 +288,7 @@                   updateBuf buf   where     getMoreData (ConnectionTLS tlsctx) = TLS.recvData tlsctx+    getMoreData (ConnectionSocket sock) = N.recv sock 1500     getMoreData (ConnectionStream h)   = B.hGetSome h (16 * 1024)      updateBuf buf = case f buf of (a, !buf') -> return (Just buf', a)@@ -278,6 +353,7 @@ connectionClose :: Connection -> IO () connectionClose = withBackend backendClose     where backendClose (ConnectionTLS ctx)  = TLS.bye ctx >> TLS.contextClose ctx+          backendClose (ConnectionSocket sock) = N.close sock           backendClose (ConnectionStream h) = hClose h  -- | Activate secure layer using the parameters specified.@@ -298,15 +374,18 @@         case backend of             (ConnectionStream h) -> do ctx <- tlsEstablish h (makeTLSParams cg (connectionID connection) params)                                        return (ConnectionTLS ctx, Just B.empty)+            (ConnectionSocket s) -> do ctx <- tlsEstablish s (makeTLSParams cg (connectionID connection) params)+                                       return (ConnectionTLS ctx, Just B.empty)             (ConnectionTLS _)    -> return (backend, b)  -- | Returns if the connection is establish securely or not. connectionIsSecure :: Connection -> IO Bool connectionIsSecure conn = withBackend isSecure conn     where isSecure (ConnectionStream _) = return False+          isSecure (ConnectionSocket _) = return False           isSecure (ConnectionTLS _)    = return True -tlsEstablish :: Handle -> TLS.ClientParams -> IO TLS.Context+tlsEstablish :: TLS.HasBackend backend => backend -> TLS.ClientParams -> IO TLS.Context tlsEstablish handle tlsParams = do     ctx <- TLS.contextNew handle tlsParams     TLS.handshake ctx
Network/Connection/Types.hs view
@@ -17,13 +17,14 @@ import Data.ByteString (ByteString)  import Network.BSD (HostName)-import Network.Socket (PortNumber)+import Network.Socket (PortNumber, Socket) import qualified Network.TLS as TLS  import System.IO (Handle)  -- | Simple backend enumeration, either using a raw connection or a tls connection. data ConnectionBackend = ConnectionStream Handle+                       | ConnectionSocket Socket                        | ConnectionTLS TLS.Context  -- | Connection Parameters to establish a Connection.
connection.cabal view
@@ -1,5 +1,5 @@ Name:                connection-Version:             0.2.5+Version:             0.2.6 Description:     Simple network library for all your connection need.     .@@ -29,7 +29,7 @@                    , data-default-class                    , network >= 2.3                    , tls >= 1.3-                   , socks >= 0.4+                   , socks >= 0.5.5                    , x509 >= 1.5                    , x509-store >= 1.5                    , x509-system >= 1.5@@ -40,4 +40,4 @@  source-repository head   type: git-  location: git://github.com/vincenthz/hs-connection+  location: https://github.com/vincenthz/hs-connection