diff --git a/ChangeLog.md b/ChangeLog.md
new file mode 100644
--- /dev/null
+++ b/ChangeLog.md
@@ -0,0 +1,3 @@
+# Changelog for keep-alive
+
+## Unreleased changes
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -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.
diff --git a/README.md b/README.md
new file mode 100644
--- /dev/null
+++ b/README.md
@@ -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.
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,2 @@
+import Distribution.Simple
+main = defaultMain
diff --git a/cbits/Cka.c b/cbits/Cka.c
new file mode 100644
--- /dev/null
+++ b/cbits/Cka.c
@@ -0,0 +1,3 @@
+#define INLINE
+#include "CKa.h"
+
diff --git a/keep-alive.cabal b/keep-alive.cabal
new file mode 100644
--- /dev/null
+++ b/keep-alive.cabal
@@ -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
diff --git a/src/LibForeign.hsc b/src/LibForeign.hsc
new file mode 100644
--- /dev/null
+++ b/src/LibForeign.hsc
@@ -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
+
diff --git a/src/Network/Socket/KeepAlive.hs b/src/Network/Socket/KeepAlive.hs
new file mode 100644
--- /dev/null
+++ b/src/Network/Socket/KeepAlive.hs
@@ -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
+
diff --git a/test/Spec.hs b/test/Spec.hs
new file mode 100644
--- /dev/null
+++ b/test/Spec.hs
@@ -0,0 +1,2 @@
+main :: IO ()
+main = putStrLn "Test suite not yet implemented"
