keep-alive (empty) → 0.1.0.0
raw patch · 9 files changed
+361/−0 lines, 9 filesdep +basedep +keep-alivesetup-changed
Dependencies added: base, keep-alive
Files
- ChangeLog.md +3/−0
- LICENSE +30/−0
- README.md +25/−0
- Setup.hs +2/−0
- cbits/Cka.c +3/−0
- keep-alive.cabal +60/−0
- src/LibForeign.hsc +116/−0
- src/Network/Socket/KeepAlive.hs +120/−0
- test/Spec.hs +2/−0
+ ChangeLog.md view
@@ -0,0 +1,3 @@+# Changelog for keep-alive++## Unreleased changes
+ LICENSE view
@@ -0,0 +1,30 @@+Copyright Kyriakos Papachrysanthou (c) 2020++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++ * Redistributions of source code must retain the above copyright+ notice, this list of conditions and the following disclaimer.++ * Redistributions in binary form must reproduce the above+ copyright notice, this list of conditions and the following+ disclaimer in the documentation and/or other materials provided+ with the distribution.++ * Neither the name of Author name here nor the names of other+ contributors may be used to endorse or promote products derived+ from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ README.md view
@@ -0,0 +1,25 @@+# keep-alive++This module allows you to set per-connection keep alive parameters on windows and linux enviroments.+For more information on keep alive signals see <https://en.wikipedia.org/wiki/Keepalive>.+See also <https://tldp.org/HOWTO/html_single/TCP-Keepalive-HOWTO/> for a linux specific implementation.++The module is meant to be used in conjuction with the "network" package. However, in order to ensure adaptability, all functions require+a socket file descriptor instead of an implementation dependent socket type. For the network package, such a descriptor can be obtained+with the withFdSocket function:++```hs+ -- sock is a Socket type+ withFdSocket sock $ \fd -> do+ before <- getKeepAliveOnOff fd+ print before -- False+ -- set keep alive on, idle 60 seconds, interval 2 seconds+ rlt <- setKeepAlive fd $ KeepAlive True 60 2+ case rlt of+ Left err -> print err+ Right () -> return ()+ after <- getKeepAliveOnOff fd+ print after -- True+```++Please note that only the envocing process can manipulate sockets based on their file descriptors.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ cbits/Cka.c view
@@ -0,0 +1,3 @@+#define INLINE+#include "CKa.h"+
+ keep-alive.cabal view
@@ -0,0 +1,60 @@+cabal-version: 1.12++-- This file has been generated from package.yaml by hpack version 0.33.0.+--+-- see: https://github.com/sol/hpack+--+-- hash: e4fadd87f6fc7f6bca702c40ec776acd3dc1b4562423d193979808778831f6b8++name: keep-alive+version: 0.1.0.0+homepage: https://github.com/3kyro/keep-alive#readme+bug-reports: https://github.com/3kyro/keep-alive/issues+author: Kyriakos Papachrysanthou+maintainer: papachrysanthou.k@gmail.com+copyright: 2020 Kyriakos Papachrysanthou+license: BSD3+license-file: LICENSE+build-type: Simple+synopsis: TCP keep alive implementation+category: Network+description:+ This module allows you to set per-connection keep alive parameters on windows and linux enviroments.+ For more information on keep alive signals see <https://en.wikipedia.org/wiki/Keepalive>.+ See also <https://tldp.org/HOWTO/html_single/TCP-Keepalive-HOWTO/> for a linux specific implementation.++extra-source-files:+ README.md+ ChangeLog.md++source-repository head+ type: git+ location: https://github.com/3kyro/keep-alive++library+ exposed-modules:+ Network.Socket.KeepAlive+ other-modules:+ LibForeign+ Paths_keep_alive+ hs-source-dirs:+ src+ build-depends:+ base >=4.7 && <5+ include-dirs:+ cbits/+ c-sources: cbits/Cka.c+ default-language: Haskell2010++test-suite keep-alive-test+ type: exitcode-stdio-1.0+ main-is: Spec.hs+ other-modules:+ Paths_keep_alive+ hs-source-dirs:+ test+ ghc-options: -threaded -rtsopts -with-rtsopts=-N+ build-depends:+ base >=4.7 && <5+ , keep-alive+ default-language: Haskell2010
+ src/LibForeign.hsc view
@@ -0,0 +1,116 @@+{-# LANGUAGE CPP, ForeignFunctionInterface #-}+module LibForeign where++import Foreign+import Foreign.C.Types+import Foreign.C.Error+import Data.Word (Word32)++-- Platform specific includes+#ifdef _WIN32 ++# include "CKa.h"++#else++#include <netinet/tcp.h>++#endif+++getKeepAliveOnOff_ :: CInt -> IO CInt+getKeepAliveOnOff_ fd =+ alloca $ \ptr -> do+ let sz = fromIntegral $ sizeOf ( undefined :: CInt)+ with sz $ \ptr_sz -> do+ c_getsockopt fd c_SOL_SOCKET c_SO_KEEPALIVE ptr ptr_sz+ peek ptr++#ifdef _WIN32++setKeepAlive_ :: CInt -> Word32 -> Word32 -> Word32 -> IO CInt+setKeepAlive_ fd onoff idle intvl =+ c_winSetKeepAlive fd (fromIntegral onoff) (fromIntegral $ idle * 1000) (fromIntegral $ intvl * 1000)++#else++setKeepAlive_ :: CInt -> Word32 -> Word32 -> Word32 -> IO CInt+setKeepAlive_ fd onoff idle intvl = do++ let intOnOff = fromInteger $ toInteger onoff+ let intIdle = fromInteger $ toInteger idle+ let intIntvl = fromInteger $ toInteger intvl++ onoffrtn <- setKeepAliveOption_ fd c_SOL_SOCKET c_SO_KEEPALIVE intOnOff+ idlertn <- setKeepAliveOption_ fd c_SOL_TCP c_TCP_KEEPIDLE intIdle+ intrtn <- setKeepAliveOption_ fd c_SOL_TCP c_TCP_KEEPINTVL intIntvl++ -- Error check+ Errno rtn <-+ if onoffrtn + idlertn + intrtn /= 0+ then getErrno+ else return $ Errno 0+ return rtn++getKeepAliveOption_ :: CInt -> CInt -> CInt -> IO Int+getKeepAliveOption_ fd level option =+ alloca $ \ptr -> do+ let sz = fromIntegral $ sizeOf ( undefined :: CInt)+ with sz $ \ptr_sz -> do+ c_getsockopt fd level option ptr ptr_sz+ peek ptr++setKeepAliveOption_ :: CInt -> CInt -> CInt -> CInt -> IO CInt+setKeepAliveOption_ fd level option value = do+ let sz = fromIntegral $ sizeOf ( undefined :: Int)+ with value $ \ptr ->+ c_setsockopt fd level option ptr sz+++#endif++c_SOL_SOCKET_ = #const SOL_SOCKET++c_SOL_SOCKET :: CInt+c_SOL_SOCKET = fromIntegral c_SOL_SOCKET_++c_SO_KEEPALIVE_ = #const SO_KEEPALIVE+ +c_SO_KEEPALIVE :: CInt+c_SO_KEEPALIVE = fromIntegral c_SO_KEEPALIVE_++#ifdef _WIN32++foreign import ccall unsafe "winSetKeepAlive" + c_winSetKeepAlive :: CInt -> CULong -> CULong -> CULong -> IO CInt ++#else++c_SOL_TCP_ = #const SOL_TCP++c_SOL_TCP :: CInt+c_SOL_TCP = fromIntegral c_SOL_TCP_++c_TCP_KEEPIDLE_ = #const TCP_KEEPIDLE++c_TCP_KEEPIDLE :: CInt+c_TCP_KEEPIDLE = fromIntegral c_TCP_KEEPIDLE_ +++c_TCP_KEEPCNT_ = #const TCP_KEEPCNT ++c_TCP_KEEPCNT :: CInt+c_TCP_KEEPCNT = fromIntegral c_TCP_KEEPCNT_++c_TCP_KEEPINTVL_ = #const TCP_KEEPINTVL++c_TCP_KEEPINTVL :: CInt +c_TCP_KEEPINTVL = fromIntegral c_TCP_KEEPINTVL_ ++#endif++foreign import ccall unsafe "getsockopt"+ c_getsockopt :: CInt -> CInt -> CInt -> Ptr a -> Ptr CInt -> IO CInt +foreign import ccall unsafe "setsockopt"+ c_setsockopt :: CInt -> CInt -> CInt -> Ptr a -> CInt -> IO CInt+
+ src/Network/Socket/KeepAlive.hs view
@@ -0,0 +1,120 @@+{-# LANGUAGE CPP #-}++-----------------------------------------------------------------------------+-- |+-- This module allows you to set per-connection keep alive parameters on windows and linux enviroments.+-- For more information on keep alive signals see https://en.wikipedia.org/wiki/Keepalive.+-- See also https://tldp.org/HOWTO/html_single/TCP-Keepalive-HOWTO/ for a linux specific implementation.+--+-- The module is meant to be used in conjuction with the "network" package. However, in order to ensure adaptability, all functions require+-- a socket file descriptor instead of an implementation dependent socket type. For the network package, such a descriptor can be obtained+-- with the withFdSocket function:+--+-- > -- sock is a Socket type+-- > withFdSocket sock $ \fd -> do+-- > before <- getKeepAliveOnOff fd+-- > print before -- False+-- > -- set keep alive on, idle 60 seconds, interval 2 seconds+-- > rlt <- setKeepAlive fd $ KeepAlive True 60 2+-- > case rlt of+-- > Left err -> print err+-- > Right () -> return ()+-- > after <- getKeepAliveOnOff fd+-- > print after -- True+--+-- Please note that only the envocing process can manipulate sockets based on their file descriptors.++module Network.Socket.KeepAlive+ ( KeepAlive (..)+ , KeepAliveError (..)+ , setKeepAlive+ , getKeepAliveOnOff+ ) where++import Data.Word (Word32)+import Foreign+import Foreign.C+import LibForeign+++-- | The main data structure defining keep alive parameters+data KeepAlive = KeepAlive+ { kaOnOff :: Bool+ -- ^ Turns on / off keep alive probes+ , kaIdle :: Word32+ -- ^ The interval in seconds between the last data packet sent and the first keep alive probe+ , kaIntvl :: Word32+ -- ^ The interval in seconds between subsequential keepalive probes+ }+ deriving (Show, Eq, Ord)++-- | Errors starting with WSA are windows specific+data KeepAliveError = WSA_IO_PENDING+ | WSA_OPERATION_ABORTED+ | WSAEFAULT+ | WSAEINPROGRESS+ | WSAEINTR+ | WSAEINVAL+ | WSAENETDOWN+ | WSAENOPROTOOPT+ | WSAENOTSOCK+ | WSAEOPNOTSUPP+ | EBADF+ | EDOM+ | EINVAL+ | EISCONN+ | ENOPROTOOPT+ | ENOTSOCK+ | ENOMEM+ | ENOBUFS+ | OTHER_KEEPALIVE_ERROR+ deriving (Show, Eq, Ord)++-- | Set keep alive parameters for the current socket+setKeepAlive ::+ CInt+ -- ^ Socket file descriptor+ -> KeepAlive+ -- ^ Keep alive parameters+ -> IO ( Either KeepAliveError ())+setKeepAlive fd (KeepAlive onoff idle intvl) = do+ rlt <- setKeepAlive_ fd (cFromBool onoff) idle intvl+ return $ case rlt of+ 0 -> Right ()+ 997 -> Left WSA_IO_PENDING+ 995 -> Left WSA_OPERATION_ABORTED+ 10014 -> Left WSAEFAULT+ 10036 -> Left WSAEINPROGRESS+ 10004 -> Left WSAEINTR+ 10022 -> Left WSAEINVAL+ 10050 -> Left WSAENETDOWN+ 10042 -> Left WSAENOPROTOOPT+ 10038 -> Left WSAENOTSOCK+ 10045 -> Left WSAEOPNOTSUPP+ 9 -> Left EBADF+ 33 -> Left EDOM+ 22 -> Left EINVAL+ 106 -> Left EISCONN+ 92 -> Left ENOPROTOOPT+ 88 -> Left ENOTSOCK+ 12 -> Left ENOMEM+ 105 -> Left ENOBUFS+ _ -> Left OTHER_KEEPALIVE_ERROR++-- | Returns True if keep alive is active for the specified socket+getKeepAliveOnOff ::+ CInt+ -- ^ Socket file descriptor+ -> IO Bool+getKeepAliveOnOff fd =+ cToBool . fromInteger . toInteger <$> getKeepAliveOnOff_ fd++cToBool :: Int -> Bool+cToBool x+ | x == 0 = False+ | otherwise = True++cFromBool :: Bool -> Word32+cFromBool True = 1+cFromBool False = 0+
+ test/Spec.hs view
@@ -0,0 +1,2 @@+main :: IO ()+main = putStrLn "Test suite not yet implemented"