diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,33 @@
+## Version 2.6.3.0
+
+ * New maintainers: Evan Borden (@eborden) and Kazu Yamamoto (@kazu-yamamoto).
+   The maintainer for a long period, Johan Tibell (@tibbe) stepped down.
+   Thank you, Johan, for your hard work for a long time.
+
+ * New APIs: ntohl, htonl,hostAddressToTuple{,6} and tupleToHostAddress{,6}.
+   [#210](https://github.com/haskell/network/pull/210)
+
+ * Added a Read instance for PortNumber. [#145](https://github.com/haskell/network/pull/145)
+
+ * We only set the IPV6_V6ONLY flag to 0 for stream and datagram socket types,
+   as opposed to all of them. This makes it possible to use ICMPv6.
+   [#180](https://github.com/haskell/network/pull/180)
+   [#181](https://github.com/haskell/network/pull/181)
+
+ * Work around GHC bug #12020. Socket errors no longer cause segfaults or
+   hangs on Windows. [#192](https://github.com/haskell/network/pull/192)
+
+ * Various documentation improvements and the deprecated pragmas.
+   [#186](https://github.com/haskell/network/pull/186)
+   [#201](https://github.com/haskell/network/issues/201)
+   [#205](https://github.com/haskell/network/pull/205)
+   [#206](https://github.com/haskell/network/pull/206)
+   [#211](https://github.com/haskell/network/issues/211)
+
+ * Various internal improvements.
+   [#193](https://github.com/haskell/network/pull/193)
+   [#200](https://github.com/haskell/network/pull/200)
+
 ## Version 2.6.2.1
 
  * Regenerate configure and HsNetworkConfig.h.in.
diff --git a/Network.hs b/Network.hs
--- a/Network.hs
+++ b/Network.hs
@@ -57,11 +57,9 @@
 
     -- ** Improving I\/O Performance over sockets
     {-$performance-}
-
-    -- ** @SIGPIPE@
-    {-$sigpipe-}
     ) where
 
+import Control.Exception (throwIO)
 import Control.Monad (liftM)
 import Data.Maybe (fromJust)
 import Network.BSD
@@ -83,7 +81,7 @@
 data PortID =
           Service String                -- Service Name eg "ftp"
         | PortNumber PortNumber         -- User defined Port Number
-#if !defined(mingw32_HOST_OS) && !defined(cygwin32_HOST_OS) && !defined(_WIN32)
+#if !defined(mingw32_HOST_OS)
         | UnixSocket String             -- Unix family socket in file system
 #endif
         deriving (Show, Eq)
@@ -130,7 +128,7 @@
         )
 #endif
 
-#if !defined(mingw32_HOST_OS) && !defined(cygwin32_HOST_OS) && !defined(_WIN32)
+#if !defined(mingw32_HOST_OS)
 connectTo _ (UnixSocket path) = do
     bracketOnError
         (socket AF_UNIX Stream 0)
@@ -198,7 +196,7 @@
         (\sock -> do
             port    <- getServicePortNumber serv
             setSocketOption sock ReuseAddr 1
-            bindSocket sock (SockAddrInet port iNADDR_ANY)
+            bind sock (SockAddrInet port iNADDR_ANY)
             listen sock maxListenQueue
             return sock
         )
@@ -210,20 +208,20 @@
         (sClose)
         (\sock -> do
             setSocketOption sock ReuseAddr 1
-            bindSocket sock (SockAddrInet port iNADDR_ANY)
+            bind sock (SockAddrInet port iNADDR_ANY)
             listen sock maxListenQueue
             return sock
         )
 #endif
 
-#if !defined(mingw32_HOST_OS) && !defined(cygwin32_HOST_OS) && !defined(_WIN32)
+#if !defined(mingw32_HOST_OS)
 listenOn (UnixSocket path) =
     bracketOnError
         (socket AF_UNIX Stream 0)
         (sClose)
         (\sock -> do
             setSocketOption sock ReuseAddr 1
-            bindSocket sock (SockAddrUnix path)
+            bind sock (SockAddrUnix path)
             listen sock maxListenQueue
             return sock
         )
@@ -250,7 +248,7 @@
         (sClose)
         (\sock -> do
             setSocketOption sock ReuseAddr 1
-            bindSocket sock (addrAddress addr)
+            bind sock (addrAddress addr)
             listen sock maxListenQueue
             return sock
         )
@@ -292,9 +290,16 @@
          \_ -> case addr of
                  SockAddrInet  _   a   -> inet_ntoa a
                  SockAddrInet6 _ _ a _ -> return (show a)
-# if !defined(mingw32_HOST_OS) && !defined(cygwin32_HOST_OS) && !defined(_WIN32)
+#if defined(mingw32_HOST_OS)
+                 SockAddrUnix {}       -> throwIO $ userError "accept: socket address not supported on this platform."
+#else
                  SockAddrUnix      a   -> return a
-# endif
+#endif
+#if defined(CAN_SOCKET_SUPPORT)
+                 SockAddrCan {}        -> throwIO $ userError "accept: unsupported for CAN peer."
+#else
+                 SockAddrCan {}        -> throwIO $ userError "accept: socket address not supported on this platform."
+#endif
  handle <- socketToHandle sock' ReadWriteMode
  let port = case addr of
               SockAddrInet  p _     -> p
@@ -302,7 +307,7 @@
               _                     -> -1
  return (handle, peer, port)
 #endif
-#if !defined(mingw32_HOST_OS) && !defined(cygwin32_HOST_OS) && !defined(_WIN32)
+#if !defined(mingw32_HOST_OS)
 accept sock@(MkSocket _ AF_UNIX _ _ _) = do
  ~(sock', (SockAddrUnix path)) <- Socket.accept sock
  handle <- socketToHandle sock' ReadWriteMode
@@ -312,10 +317,10 @@
   error $ "Sorry, address family " ++ (show family) ++ " is not supported!"
 
 
--- | Close the socket. All future operations on the socket object will fail.
---   The remote end will receive no more data (after queued data is flushed).
+-- | Close the socket. Sending data to or receiving data from closed socket
+-- may lead to undefined behaviour.
 sClose :: Socket -> IO ()
-sClose = close -- Explicit redefinition because Network.sClose is deperecated,
+sClose = close -- Explicit redefinition because Network.sClose is deprecated,
                -- hence the re-export would also be marked as such.
 
 -- -----------------------------------------------------------------------------
@@ -395,17 +400,19 @@
 socketPort :: Socket -> IO PortID
 socketPort s = do
     sockaddr <- getSocketName s
-    return (portID sockaddr)
-  where
-   portID sa =
-    case sa of
-     SockAddrInet port _      -> PortNumber port
+    case sockaddr of
+      SockAddrInet port _      -> return $ PortNumber port
 #if defined(IPV6_SOCKET_SUPPORT)
-     SockAddrInet6 port _ _ _ -> PortNumber port
+      SockAddrInet6 port _ _ _ -> return $ PortNumber port
+#else
+      SockAddrInet6 {}         -> throwIO $ userError "socketPort: socket address not supported on this platform."
 #endif
-#if !defined(mingw32_HOST_OS) && !defined(cygwin32_HOST_OS) && !defined(_WIN32)
-     SockAddrUnix path        -> UnixSocket path
+#if defined(mingw32_HOST_OS)
+      SockAddrUnix {}          -> throwIO $ userError "socketPort: socket address not supported on this platform."
+#else
+      SockAddrUnix path        -> return $ UnixSocket path
 #endif
+      SockAddrCan {}           -> throwIO $ userError "socketPort: CAN address not supported."
 
 -- ---------------------------------------------------------------------------
 -- Utils
@@ -437,21 +444,6 @@
 
 For really fast I\/O, it might be worth looking at the 'hGetBuf' and
 'hPutBuf' family of functions in "System.IO".
--}
-
-{-$sigpipe
-
-On Unix, when writing to a socket and the reading end is
-closed by the remote client, the program is normally sent a
-@SIGPIPE@ signal by the operating system.  The
-default behaviour when a @SIGPIPE@ is received is
-to terminate the program silently, which can be somewhat confusing
-if you haven't encountered this before.  The solution is to
-specify that @SIGPIPE@ is to be ignored, using
-the POSIX library:
-
->  import Posix
->  main = do installHandler sigPIPE Ignore Nothing; ...
 -}
 
 catchIO :: IO a -> (Exception.IOException -> IO a) -> IO a
diff --git a/Network/BSD.hsc b/Network/BSD.hsc
--- a/Network/BSD.hsc
+++ b/Network/BSD.hsc
@@ -27,7 +27,7 @@
     , getHostByAddr
     , hostAddress
 
-#if defined(HAVE_GETHOSTENT) && !defined(cygwin32_HOST_OS) && !defined(mingw32_HOST_OS) && !defined(_WIN32)
+#if defined(HAVE_GETHOSTENT) && !defined(mingw32_HOST_OS)
     , getHostEntries
 
     -- ** Low level functionality
@@ -43,7 +43,7 @@
     , getServiceByPort
     , getServicePortNumber
 
-#if !defined(cygwin32_HOST_OS) && !defined(mingw32_HOST_OS) && !defined(_WIN32)
+#if !defined(mingw32_HOST_OS)
     , getServiceEntries
 
     -- ** Low level functionality
@@ -61,7 +61,7 @@
     , getProtocolNumber
     , defaultProtocol
 
-#if !defined(cygwin32_HOST_OS) && !defined(mingw32_HOST_OS) && !defined(_WIN32)
+#if !defined(mingw32_HOST_OS)
     , getProtocolEntries
     -- ** Low level functionality
     , setProtocolEntry
@@ -77,7 +77,7 @@
     , NetworkAddr
     , NetworkEntry(..)
 
-#if !defined(cygwin32_HOST_OS) && !defined(mingw32_HOST_OS) && !defined(_WIN32)
+#if !defined(mingw32_HOST_OS)
     , getNetworkByName
     , getNetworkByAddr
     , getNetworkEntries
@@ -99,7 +99,7 @@
 import Control.Concurrent (MVar, newMVar, withMVar)
 import qualified Control.Exception as E
 import Foreign.C.String (CString, peekCString, withCString)
-#if defined(HAVE_WINSOCK2_H) && !defined(cygwin32_HOST_OS)
+#if defined(HAVE_WINSOCK2_H)
 import Foreign.C.Types ( CShort )
 #endif
 import Foreign.C.Types ( CInt(..), CUInt(..), CULong(..), CSize(..) )
@@ -158,12 +158,12 @@
         return (ServiceEntry {
                         serviceName     = s_name,
                         serviceAliases  = s_aliases,
-#if defined(HAVE_WINSOCK2_H) && !defined(cygwin32_HOST_OS)
-                        servicePort     = PortNum (fromIntegral (s_port :: CShort)),
+#if defined(HAVE_WINSOCK2_H)
+                        servicePort     = (fromIntegral (s_port :: CShort)),
 #else
                            -- s_port is already in network byte order, but it
                            -- might be the wrong size.
-                        servicePort     = PortNum (fromIntegral (s_port :: CInt)),
+                        servicePort     = (fromIntegral (s_port :: CInt)),
 #endif
                         serviceProtocol = s_proto
                 })
@@ -187,7 +187,7 @@
 
 -- | Get the service given a 'PortNumber' and 'ProtocolName'.
 getServiceByPort :: PortNumber -> ProtocolName -> IO ServiceEntry
-getServiceByPort (PortNum port) proto = withLock $ do
+getServiceByPort port proto = withLock $ do
  withCString proto $ \ cstr_proto -> do
  throwNoSuchThingIfNull "getServiceByPort" "no such service entry"
    $ c_getservbyport (fromIntegral port) cstr_proto
@@ -202,7 +202,7 @@
     (ServiceEntry _ _ port _) <- getServiceByName name "tcp"
     return port
 
-#if !defined(cygwin32_HOST_OS) && !defined(mingw32_HOST_OS) && !defined(_WIN32)
+#if !defined(mingw32_HOST_OS)
 getServiceEntry :: IO ServiceEntry
 getServiceEntry = withLock $ do
  throwNoSuchThingIfNull "getServiceEntry" "no such service entry"
@@ -255,7 +255,7 @@
         p_aliases <- (#peek struct protoent, p_aliases) p
                            >>= peekArray0 nullPtr
                            >>= mapM peekCString
-#if defined(HAVE_WINSOCK2_H) && !defined(cygwin32_HOST_OS)
+#if defined(HAVE_WINSOCK2_H)
          -- With WinSock, the protocol number is only a short;
          -- hoist it in as such, but represent it on the Haskell side
          -- as a CInt.
@@ -298,7 +298,7 @@
  (ProtocolEntry _ _ num) <- getProtocolByName proto
  return num
 
-#if !defined(cygwin32_HOST_OS) && !defined(mingw32_HOST_OS) && !defined(_WIN32)
+#if !defined(mingw32_HOST_OS)
 getProtocolEntry :: IO ProtocolEntry    -- Next Protocol Entry from DB
 getProtocolEntry = withLock $ do
  ent <- throwNoSuchThingIfNull "getProtocolEntry" "no such protocol entry"
@@ -351,7 +351,7 @@
         return (HostEntry {
                         hostName       = h_name,
                         hostAliases    = h_aliases,
-#if defined(HAVE_WINSOCK2_H) && !defined(cygwin32_HOST_OS)
+#if defined(HAVE_WINSOCK2_H)
                         hostFamily     = unpackFamily (fromIntegral (h_addrtype :: CShort)),
 #else
                         hostFamily     = unpackFamily h_addrtype,
@@ -397,7 +397,7 @@
 foreign import CALLCONV safe "gethostbyaddr"
    c_gethostbyaddr :: Ptr HostAddress -> CInt -> CInt -> IO (Ptr HostEntry)
 
-#if defined(HAVE_GETHOSTENT) && !defined(cygwin32_HOST_OS) && !defined(mingw32_HOST_OS) && !defined(_WIN32)
+#if defined(HAVE_GETHOSTENT) && !defined(mingw32_HOST_OS)
 getHostEntry :: IO HostEntry
 getHostEntry = withLock $ do
  throwNoSuchThingIfNull         "getHostEntry" "unable to retrieve host entry"
@@ -463,7 +463,7 @@
    poke _p = error "Storable.poke(BSD.NetEntry) not implemented"
 
 
-#if !defined(cygwin32_HOST_OS) && !defined(mingw32_HOST_OS) && !defined(_WIN32)
+#if !defined(mingw32_HOST_OS)
 getNetworkByName :: NetworkName -> IO NetworkEntry
 getNetworkByName name = withLock $ do
  withCString name $ \ name_cstr -> do
diff --git a/Network/Socket.hsc b/Network/Socket.hsc
--- a/Network/Socket.hsc
+++ b/Network/Socket.hsc
@@ -36,11 +36,17 @@
     , isSupportedSockAddr
     , SocketStatus(..)
     , HostAddress
+    , hostAddressToTuple
+    , tupleToHostAddress
 #if defined(IPV6_SOCKET_SUPPORT)
     , HostAddress6
+    , hostAddress6ToTuple
+    , tupleToHostAddress6
     , FlowInfo
     , ScopeID
 #endif
+    , htonl
+    , ntohl
     , ShutdownCmd(..)
     , ProtocolNumber
     , defaultProtocol
@@ -83,7 +89,7 @@
 #if defined(HAVE_STRUCT_UCRED) || defined(HAVE_GETPEEREID)
     -- get the credentials of our domain socket peer.
     , getPeerCred
-#if defined(HAVE_GETPEEREID) 
+#if defined(HAVE_GETPEEREID)
     , getPeerEid
 #endif
 #endif
@@ -93,19 +99,21 @@
     , socketToHandle
 
     -- ** Sending and receiving data
+    -- *** Sending and receiving with String
     -- $sendrecv
-    , sendTo
-    , sendBufTo
-
-    , recvFrom
-    , recvBufFrom
-
     , send
+    , sendTo
     , recv
+    , recvFrom
     , recvLen
+
+    -- *** Sending and receiving with a buffer
     , sendBuf
     , recvBuf
+    , sendBufTo
+    , recvBufFrom
 
+    -- ** Misc
     , inet_addr
     , inet_ntoa
 
@@ -174,7 +182,8 @@
     ) where
 
 import Data.Bits
-import Data.List (delete, foldl')
+import Data.Functor
+import Data.List (foldl')
 import Data.Maybe (isJust)
 import Data.Word (Word8, Word32)
 import Foreign.Ptr (Ptr, castPtr, nullPtr)
@@ -190,7 +199,6 @@
 import System.IO
 import Control.Monad (liftM, when)
 
-import qualified Control.Exception as E
 import Control.Concurrent.MVar
 import Data.Typeable
 import System.IO.Error
@@ -200,20 +208,25 @@
 import GHC.Conc (closeFdWith)
 ##endif
 # if defined(mingw32_HOST_OS)
+import qualified Control.Exception as E
 import GHC.Conc (asyncDoProc)
+import GHC.IO.FD (FD(..), readRawBufferPtr, writeRawBufferPtr)
 import Foreign (FunPtr)
 # endif
+# if defined(darwin_HOST_OS)
+import Data.List (delete)
+# endif
 import qualified GHC.IO.Device
 import GHC.IO.Handle.FD
 import GHC.IO.Exception
 import GHC.IO
 import qualified System.Posix.Internals
 
-import GHC.IO.FD
-
 import Network.Socket.Internal
 import Network.Socket.Types
 
+import Prelude -- Silence AMP warnings
+
 -- | Either a host name e.g., @\"haskell.org\"@ or a numeric host
 -- address string consisting of a dotted decimal IPv4 address or an
 -- IPv6 address e.g., @\"192.168.0.1\"@.
@@ -288,6 +301,9 @@
    . showString "]:"
    . shows port
 #endif
+#if defined(CAN_SOCKET_SUPPORT)
+  showsPrec _ (SockAddrCan ifidx) = shows ifidx
+#endif
 
 -----------------------------------------------------------------------------
 -- Connection Functions
@@ -303,8 +319,20 @@
 -- and protocol number.  The address family is usually 'AF_INET',
 -- 'AF_INET6', or 'AF_UNIX'.  The socket type is usually 'Stream' or
 -- 'Datagram'.  The protocol number is usually 'defaultProtocol'.
--- If 'AF_INET6' is used, the 'IPv6Only' socket option is set to 0
--- so that both IPv4 and IPv6 can be handled with one socket.
+-- If 'AF_INET6' is used and the socket type is 'Stream' or 'Datagram',
+-- the 'IPv6Only' socket option is set to 0 so that both IPv4 and IPv6
+-- can be handled with one socket.
+--
+-- >>> let hints = defaultHints { addrFlags = [AI_NUMERICHOST, AI_NUMERICSERV], addrSocketType = Stream }
+-- >>> addr:_ <- getAddrInfo (Just hints) (Just "127.0.0.1") (Just "5000")
+-- >>> sock@(MkSocket _ fam stype _ _) <- socket (addrFamily addr) (addrSocketType addr) (addrProtocol addr)
+-- >>> fam
+-- AF_INET
+-- >>> stype
+-- Stream
+-- >>> bind sock (addrAddress addr)
+-- >>> getSocketName sock
+-- 127.0.0.1:5000
 socket :: Family         -- Family Name (usually AF_INET)
        -> SocketType     -- Socket Type (usually Stream)
        -> ProtocolNumber -- Protocol Number (getProtocolByName to find value)
@@ -318,13 +346,16 @@
     withSocketsDo $ return ()
     let sock = MkSocket fd family stype protocol socket_status
 #if HAVE_DECL_IPV6_V6ONLY
+    -- The default value of the IPv6Only option is platform specific,
+    -- so we explicitly set it to 0 to provide a common default.
 # if defined(mingw32_HOST_OS)
-    -- the IPv6Only option is only supported on Windows Vista and later,
-    -- so trying to change it might throw an error
-    when (family == AF_INET6) $
-            E.catch (setSocketOption sock IPv6Only 0) $ (\(_ :: E.IOException) -> return ())
+    -- The IPv6Only option is only supported on Windows Vista and later,
+    -- so trying to change it might throw an error.
+    when (family == AF_INET6 && (stype == Stream || stype == Datagram)) $
+      E.catch (setSocketOption sock IPv6Only 0) $ (\(_ :: E.IOException) -> return ())
 # else
-    when (family == AF_INET6) $ setSocketOption sock IPv6Only 0
+    when (family == AF_INET6 && (stype == Stream || stype == Datagram)) $
+      setSocketOption sock IPv6Only 0 `onException` close sock
 # endif
 #endif
     return sock
@@ -405,7 +436,7 @@
            r <- c_connect s p_addr (fromIntegral sz)
            if r == -1
                then do
-#if !(defined(HAVE_WINSOCK2_H) && !defined(cygwin32_HOST_OS))
+#if !(defined(HAVE_WINSOCK2_H))
                    err <- getErrno
                    case () of
                      _ | err == eINTR       -> connectLoop
@@ -520,11 +551,11 @@
 
 -- $sendrecv
 --
--- Do not use the @send@ and @recv@ functions defined in this module
+-- Do not use the @send@ and @recv@ functions defined in this section
 -- in new code, as they incorrectly represent binary data as a Unicode
 -- string.  As a result, these functions are inefficient and may lead
 -- to bugs in the program.  Instead use the @send@ and @recv@
--- functions defined in the 'Network.Socket.ByteString' module.
+-- functions defined in the "Network.Socket.ByteString" module.
 
 -----------------------------------------------------------------------------
 -- sendTo & recvFrom
@@ -536,6 +567,7 @@
 --
 -- NOTE: blocking on Windows unless you compile with -threaded (see
 -- GHC ticket #1129)
+{-# WARNING sendTo "Use sendTo defined in \"Network.Socket.ByteString\"" #-}
 sendTo :: Socket        -- (possibly) bound/connected Socket
        -> String        -- Data to send
        -> SockAddr
@@ -567,6 +599,7 @@
 --
 -- NOTE: blocking on Windows unless you compile with -threaded (see
 -- GHC ticket #1129)
+{-# WARNING recvFrom "Use recvFrom defined in \"Network.Socket.ByteString\"" #-}
 recvFrom :: Socket -> Int -> IO (String, Int, SockAddr)
 recvFrom sock nbytes =
   allocaBytes nbytes $ \ptr -> do
@@ -613,27 +646,20 @@
 -- | Send data to the socket. The socket must be connected to a remote
 -- socket. Returns the number of bytes sent.  Applications are
 -- responsible for ensuring that all data has been sent.
+--
+-- Sending data to closed socket may lead to undefined behaviour.
+{-# WARNING send "Use send defined in \"Network.Socket.ByteString\"" #-}
 send :: Socket  -- Bound/Connected Socket
      -> String  -- Data to send
      -> IO Int  -- Number of Bytes sent
-send sock@(MkSocket s _family _stype _protocol _status) xs = do
- withCStringLen xs $ \(str, len) -> do
-   liftM fromIntegral $
-#if defined(mingw32_HOST_OS)
-    writeRawBufferPtr
-      "Network.Socket.send"
-      (socket2FD sock)
-      (castPtr str)
-      0
-      (fromIntegral len)
-#else
-     throwSocketErrorWaitWrite sock "send" $
-        c_send s str (fromIntegral len) 0{-flags-}
-#endif
+send sock xs = withCStringLen xs $ \(str, len) ->
+    sendBuf sock (castPtr str) len
 
 -- | Send data to the socket. The socket must be connected to a remote
 -- socket. Returns the number of bytes sent.  Applications are
 -- responsible for ensuring that all data has been sent.
+--
+-- Sending data to closed socket may lead to undefined behaviour.
 sendBuf :: Socket     -- Bound/Connected Socket
         -> Ptr Word8  -- Pointer to the data to send
         -> Int        -- Length of the buffer
@@ -641,7 +667,11 @@
 sendBuf sock@(MkSocket s _family _stype _protocol _status) str len = do
    liftM fromIntegral $
 #if defined(mingw32_HOST_OS)
-    writeRawBufferPtr
+-- writeRawBufferPtr is supposed to handle checking for errors, but it's broken
+-- on x86_64 because of GHC bug #12010 so we duplicate the check here. The call
+-- to throwSocketErrorIfMinus1Retry can be removed when no GHC version with the
+-- bug is supported.
+    throwSocketErrorIfMinus1Retry "Network.Socket.sendBuf" $ writeRawBufferPtr
       "Network.Socket.sendBuf"
       (socket2FD sock)
       (castPtr str)
@@ -664,28 +694,19 @@
 --
 -- For TCP sockets, a zero length return value means the peer has
 -- closed its half side of the connection.
+--
+-- Receiving data from closed socket may lead to undefined behaviour.
+{-# WARNING recv "Use recv defined in \"Network.Socket.ByteString\"" #-}
 recv :: Socket -> Int -> IO String
-recv sock l = recvLen sock l >>= \ (s,_) -> return s
+recv sock l = fst <$> recvLen sock l
 
+{-# WARNING recvLen "Use recvLen defined in \"Network.Socket.ByteString\"" #-}
 recvLen :: Socket -> Int -> IO (String, Int)
-recvLen sock@(MkSocket s _family _stype _protocol _status) nbytes
- | nbytes <= 0 = ioError (mkInvalidRecvArgError "Network.Socket.recv")
- | otherwise   = do
+recvLen sock nbytes =
      allocaBytes nbytes $ \ptr -> do
-        len <-
-#if defined(mingw32_HOST_OS)
-          readRawBufferPtr "Network.Socket.recvLen" (socket2FD sock) ptr 0
-                 (fromIntegral nbytes)
-#else
-               throwSocketErrorWaitRead sock "recv" $
-                   c_recv s ptr (fromIntegral nbytes) 0{-flags-}
-#endif
-        let len' = fromIntegral len
-        if len' == 0
-         then ioError (mkEOFError "Network.Socket.recv")
-         else do
-           s' <- peekCStringLen (castPtr ptr,len')
-           return (s', len')
+        len <- recvBuf sock ptr nbytes
+        s <- peekCStringLen (castPtr ptr,len)
+        return (s, len)
 
 -- | Receive data from the socket.  The socket must be in a connected
 -- state. This function may return fewer bytes than specified.  If the
@@ -698,17 +719,18 @@
 --
 -- For TCP sockets, a zero length return value means the peer has
 -- closed its half side of the connection.
+--
+-- Receiving data from closed socket may lead to undefined behaviour.
 recvBuf :: Socket -> Ptr Word8 -> Int -> IO Int
-recvBuf sock p l = recvLenBuf sock p l
-
-recvLenBuf :: Socket -> Ptr Word8 -> Int -> IO Int
-recvLenBuf sock@(MkSocket s _family _stype _protocol _status) ptr nbytes
+recvBuf sock@(MkSocket s _family _stype _protocol _status) ptr nbytes
  | nbytes <= 0 = ioError (mkInvalidRecvArgError "Network.Socket.recvBuf")
  | otherwise   = do
         len <-
 #if defined(mingw32_HOST_OS)
-          readRawBufferPtr "Network.Socket.recvLenBuf" (socket2FD sock) ptr 0
-                 (fromIntegral nbytes)
+-- see comment in sendBuf above.
+            throwSocketErrorIfMinus1Retry "Network.Socket.recvBuf" $
+                readRawBufferPtr "Network.Socket.recvBuf"
+                (socket2FD sock) ptr 0 (fromIntegral nbytes)
 #else
                throwSocketErrorWaitRead sock "recvBuf" $
                    c_recv s (castPtr ptr) (fromIntegral nbytes) 0{-flags-}
@@ -946,11 +968,10 @@
 getPeerCred sock = do
 #ifdef HAVE_STRUCT_UCRED
   let fd = fdSocket sock
-  let sz = (fromIntegral (#const sizeof(struct ucred)))
-  with sz $ \ ptr_cr ->
-   alloca       $ \ ptr_sz -> do
-     poke ptr_sz sz
-     throwSocketErrorIfMinus1Retry "getPeerCred" $
+  let sz = (#const sizeof(struct ucred))
+  allocaBytes sz $ \ ptr_cr ->
+   with (fromIntegral sz) $ \ ptr_sz -> do
+     _ <- ($) throwSocketErrorIfMinus1Retry "getPeerCred" $
        c_getsockopt fd (#const SOL_SOCKET) (#const SO_PEERCRED) ptr_cr ptr_sz
      pid <- (#peek struct ucred, pid) ptr_cr
      uid <- (#peek struct ucred, uid) ptr_cr
@@ -965,7 +986,7 @@
 -- | The getpeereid() function returns the effective user and group IDs of the
 -- peer connected to a UNIX-domain socket
 getPeerEid :: Socket -> IO (CUInt, CUInt)
-getPeerEid sock = do 
+getPeerEid sock = do
   let fd = fdSocket sock
   alloca $ \ ptr_uid ->
     alloca $ \ ptr_gid -> do
@@ -986,7 +1007,7 @@
 -- for transmitting file descriptors, mainly.
 sendFd :: Socket -> CInt -> IO ()
 sendFd sock outfd = do
-  throwSocketErrorWaitWrite sock "sendFd" $
+  _ <- ($) throwSocketErrorWaitWrite sock "sendFd" $
      c_sendFd (fdSocket sock) outfd
    -- Note: If Winsock supported FD-passing, thi would have been
    -- incorrect (since socket FDs need to be closed via closesocket().)
@@ -1014,7 +1035,10 @@
 iNADDR_ANY :: HostAddress
 iNADDR_ANY = htonl (#const INADDR_ANY)
 
+-- | Converts the from host byte order to network byte order.
 foreign import CALLCONV unsafe "htonl" htonl :: Word32 -> Word32
+-- | Converts the from network byte order to host byte order.
+foreign import CALLCONV unsafe "ntohl" ntohl :: Word32 -> Word32
 
 #if defined(IPV6_SOCKET_SUPPORT)
 -- | The IPv6 wild card address.
@@ -1065,9 +1089,8 @@
 
 -- -----------------------------------------------------------------------------
 
--- | Close the socket.  All future operations on the socket object
--- will fail.  The remote end will receive no more data (after queued
--- data is flushed).
+-- | Close the socket. Sending data to or receiving data from closed socket
+-- may lead to undefined behaviour.
 close :: Socket -> IO ()
 close (MkSocket s _ _ _ socketStatus) = do
  modifyMVar_ socketStatus $ \ status ->
@@ -1186,13 +1209,37 @@
 #if defined(IPV6_SOCKET_SUPPORT)
 
 -- | Flags that control the querying behaviour of 'getAddrInfo'.
-data AddrInfoFlag
-    = AI_ADDRCONFIG
+--   For more information, see <https://tools.ietf.org/html/rfc3493#page-25>
+data AddrInfoFlag =
+    -- | The list of returned 'AddrInfo' values will
+    --   only contain IPv4 addresses if the local system has at least
+    --   one IPv4 interface configured, and likewise for IPv6.
+    --   (Only some platforms support this.)
+      AI_ADDRCONFIG
+    -- | If 'AI_ALL' is specified, return all matching IPv6 and
+    --   IPv4 addresses.  Otherwise, this flag has no effect.
+    --   (Only some platforms support this.)
     | AI_ALL
+    -- | The 'addrCanonName' field of the first returned
+    --   'AddrInfo' will contain the "canonical name" of the host.
     | AI_CANONNAME
+    -- | The 'HostName' argument /must/ be a numeric
+    --   address in string form, and network name lookups will not be
+    --   attempted.
     | AI_NUMERICHOST
+    -- | The 'ServiceName' argument /must/ be a port
+    --   number in string form, and service name lookups will not be
+    --   attempted. (Only some platforms support this.)
     | AI_NUMERICSERV
+    -- | If no 'HostName' value is provided, the network
+    --   address in each 'SockAddr'
+    --   will be left as a "wild card", i.e. as either 'iNADDR_ANY'
+    --   or 'iN6ADDR_ANY'.  This is useful for server applications that
+    --   will accept connections from any client.
     | AI_PASSIVE
+    -- | If an IPv6 lookup is performed, and no IPv6
+    --   addresses are found, IPv6-mapped IPv4 addresses will be
+    --   returned. (Only some platforms support this.)
     | AI_V4MAPPED
     deriving (Eq, Read, Show, Typeable)
 
@@ -1283,11 +1330,27 @@
         (#poke struct addrinfo, ai_canonname) p nullPtr
         (#poke struct addrinfo, ai_next) p nullPtr
 
-data NameInfoFlag
-    = NI_DGRAM
+-- | Flags that control the querying behaviour of 'getNameInfo'.
+--   For more information, see <https://tools.ietf.org/html/rfc3493#page-30>
+data NameInfoFlag =
+    -- | Resolve a datagram-based service name.  This is
+    --   required only for the few protocols that have different port
+    --   numbers for their datagram-based versions than for their
+    --   stream-based versions.
+      NI_DGRAM
+    -- | If the hostname cannot be looked up, an IO error is thrown.
     | NI_NAMEREQD
+    -- | If a host is local, return only the hostname part of the FQDN.
     | NI_NOFQDN
+    -- | The name of the host is not looked up.
+    --   Instead, a numeric representation of the host's
+    --   address is returned.  For an IPv4 address, this will be a
+    --   dotted-quad string.  For IPv6, it will be colon-separated
+    --   hexadecimal.
     | NI_NUMERICHOST
+    -- | The name of the service is not
+    --   looked up.  Instead, a numeric representation of the
+    --   service is returned.
     | NI_NUMERICSERV
     deriving (Eq, Read, Show, Typeable)
 
@@ -1302,9 +1365,17 @@
 -- | Default hints for address lookup with 'getAddrInfo'.  The values
 -- of the 'addrAddress' and 'addrCanonName' fields are 'undefined',
 -- and are never inspected by 'getAddrInfo'.
+--
+-- >>> addrFlags defaultHints
+-- []
+-- >>> addrFamily defaultHints
+-- AF_UNSPEC
+-- >>> addrSocketType defaultHints
+-- NoSocketType
+-- >>> addrProtocol defaultHints
+-- 0
 
 defaultHints :: AddrInfo
-
 defaultHints = AddrInfo {
                          addrFlags = [],
                          addrFamily = AF_UNSPEC,
@@ -1327,45 +1398,7 @@
 -- using Haskell's record update syntax on 'defaultHints', for example
 -- as follows:
 --
--- @
---   myHints = defaultHints { addrFlags = [AI_ADDRCONFIG, AI_CANONNAME] }
--- @
---
--- Values for 'addrFlags' control query behaviour.  The supported
--- flags are as follows:
---
---   [@AI_PASSIVE@] If no 'HostName' value is provided, the network
---     address in each 'SockAddr'
---     will be left as a "wild card", i.e. as either 'iNADDR_ANY'
---     or 'iN6ADDR_ANY'.  This is useful for server applications that
---     will accept connections from any client.
---
---   [@AI_CANONNAME@] The 'addrCanonName' field of the first returned
---     'AddrInfo' will contain the "canonical name" of the host.
---
---   [@AI_NUMERICHOST@] The 'HostName' argument /must/ be a numeric
---     address in string form, and network name lookups will not be
---     attempted.
---
--- /Note/: Although the following flags are required by RFC 3493, they
--- may not have an effect on all platforms, because the underlying
--- network stack may not support them.  To see whether a flag from the
--- list below will have any effect, call 'addrInfoFlagImplemented'.
---
---   [@AI_NUMERICSERV@] The 'ServiceName' argument /must/ be a port
---     number in string form, and service name lookups will not be
---     attempted.
---
---   [@AI_ADDRCONFIG@] The list of returned 'AddrInfo' values will
---     only contain IPv4 addresses if the local system has at least
---     one IPv4 interface configured, and likewise for IPv6.
---
---   [@AI_V4MAPPED@] If an IPv6 lookup is performed, and no IPv6
---     addresses are found, IPv6-mapped IPv4 addresses will be
---     returned.
---
---   [@AI_ALL@] If 'AI_ALL' is specified, return all matching IPv6 and
---     IPv4 addresses.  Otherwise, this flag has no effect.
+-- >>> let hints = defaultHints { addrFlags = [AI_NUMERICHOST], addrSocketType = Stream }
 --
 -- You must provide a 'Just' value for at least one of the 'HostName'
 -- or 'ServiceName' arguments.  'HostName' can be either a numeric
@@ -1388,14 +1421,9 @@
 -- for @getaddrinfo@ in RFC 2553.  The 'AddrInfo' parameter comes first
 -- to make partial application easier.
 --
--- Example:
--- @
---   let hints = defaultHints { addrFlags = [AI_ADDRCONFIG, AI_CANONNAME] }
---   addrs <- getAddrInfo (Just hints) (Just "www.haskell.org") (Just "http")
---   let addr = head addrs
---   sock <- socket (addrFamily addr) (addrSocketType addr) (addrProtocol addr)
---   connect sock (addrAddress addr)
--- @
+-- >>> addr:_ <- getAddrInfo (Just hints) (Just "127.0.0.1") (Just "http")
+-- >>> addrAddress addr
+-- 127.0.0.1:80
 
 getAddrInfo :: Maybe AddrInfo -- ^ preferred socket type or protocol
             -> Maybe HostName -- ^ host name to look up
@@ -1461,35 +1489,7 @@
 
 -- | Resolve an address to a host or service name.
 -- This function is protocol independent.
---
--- The list of 'NameInfoFlag' values controls query behaviour.  The
--- supported flags are as follows:
---
---   [@NI_NOFQDN@] If a host is local, return only the
---     hostname part of the FQDN.
---
---   [@NI_NUMERICHOST@] The name of the host is not
---     looked up.  Instead, a numeric representation of the host's
---     address is returned.  For an IPv4 address, this will be a
---     dotted-quad string.  For IPv6, it will be colon-separated
---     hexadecimal.
---
---   [@NI_NUMERICSERV@] The name of the service is not
---     looked up.  Instead, a numeric representation of the
---     service is returned.
---
---   [@NI_NAMEREQD@] If the hostname cannot be looked up, an IO error
---     is thrown.
---
---   [@NI_DGRAM@] Resolve a datagram-based service name.  This is
---     required only for the few protocols that have different port
---     numbers for their datagram-based versions than for their
---     stream-based versions.
---
--- Hostname and service name lookups can be expensive.  You can
--- specify which lookups to perform via the two 'Bool' arguments.  If
--- one of these is 'False', the corresponding value in the returned
--- tuple will be 'Nothing', and no lookup will be performed.
+-- The list of 'NameInfoFlag' values controls query behaviour.
 --
 -- If a host or service's name cannot be looked up, then the numeric
 -- form of the address or service will be returned.
@@ -1568,11 +1568,12 @@
   c_bind :: CInt -> Ptr SockAddr -> CInt{-CSockLen???-} -> IO CInt
 foreign import CALLCONV SAFE_ON_WIN "connect"
   c_connect :: CInt -> Ptr SockAddr -> CInt{-CSockLen???-} -> IO CInt
-foreign import CALLCONV unsafe "accept"
-  c_accept :: CInt -> Ptr SockAddr -> Ptr CInt{-CSockLen???-} -> IO CInt
 #ifdef HAVE_ACCEPT4
 foreign import CALLCONV unsafe "accept4"
   c_accept4 :: CInt -> Ptr SockAddr -> Ptr CInt{-CSockLen???-} -> CInt -> IO CInt
+#else
+foreign import CALLCONV unsafe "accept"
+  c_accept :: CInt -> Ptr SockAddr -> Ptr CInt{-CSockLen???-} -> IO CInt
 #endif
 foreign import CALLCONV unsafe "listen"
   c_listen :: CInt -> CInt -> IO CInt
@@ -1614,31 +1615,45 @@
 -- These aliases are deprecated and should not be used in new code.
 -- They will be removed in some future version of the package.
 
+{-# DEPRECATED bindSocket "use 'bind'" #-}
+
 -- | Deprecated alias for 'bind'.
 bindSocket :: Socket    -- Unconnected Socket
            -> SockAddr  -- Address to Bind to
            -> IO ()
 bindSocket = bind
 
+{-# DEPRECATED sClose "use 'close'" #-}
+
 -- | Deprecated alias for 'close'.
 sClose :: Socket -> IO ()
 sClose = close
 
+{-# DEPRECATED sIsConnected "use 'isConnected'" #-}
+
 -- | Deprecated alias for 'isConnected'.
 sIsConnected :: Socket -> IO Bool
 sIsConnected = isConnected
 
+{-# DEPRECATED sIsBound "use 'isBound'" #-}
+
 -- | Deprecated alias for 'isBound'.
 sIsBound :: Socket -> IO Bool
 sIsBound = isBound
 
+{-# DEPRECATED sIsListening "use 'isListening'" #-}
+
 -- | Deprecated alias for 'isListening'.
 sIsListening :: Socket -> IO Bool
 sIsListening = isListening
 
+{-# DEPRECATED sIsReadable "use 'isReadable'" #-}
+
 -- | Deprecated alias for 'isReadable'.
 sIsReadable  :: Socket -> IO Bool
 sIsReadable = isReadable
+
+{-# DEPRECATED sIsWritable "use 'isWritable'" #-}
 
 -- | Deprecated alias for 'isWritable'.
 sIsWritable  :: Socket -> IO Bool
diff --git a/Network/Socket/ByteString.hsc b/Network/Socket/ByteString.hsc
--- a/Network/Socket/ByteString.hsc
+++ b/Network/Socket/ByteString.hsc
@@ -43,15 +43,13 @@
     -- $example
     ) where
 
-import Control.Monad (liftM, when)
+import Control.Monad (when)
 import Data.ByteString (ByteString)
 import Data.ByteString.Internal (createAndTrim)
 import Data.ByteString.Unsafe (unsafeUseAsCStringLen)
-import Data.Word (Word8)
-import Foreign.C.Types (CInt(..))
 import Foreign.Marshal.Alloc (allocaBytes)
-import Foreign.Ptr (Ptr, castPtr)
-import Network.Socket (SockAddr, Socket(..), sendBufTo, recvBufFrom)
+import Foreign.Ptr (castPtr)
+import Network.Socket (sendBuf, sendBufTo, recvBuf, recvBufFrom)
 
 import qualified Data.ByteString as B
 
@@ -60,53 +58,38 @@
 import Network.Socket.Types
 
 #if !defined(mingw32_HOST_OS)
-import Control.Monad (zipWithM_)
-import Foreign.C.Types (CChar)
-import Foreign.C.Types (CSize(..))
+import Control.Monad (liftM, zipWithM_)
 import Foreign.Marshal.Array (allocaArray)
 import Foreign.Marshal.Utils (with)
-import Foreign.Ptr (plusPtr)
+import Foreign.Ptr (Ptr, plusPtr)
 import Foreign.Storable (Storable(..))
 
 import Network.Socket.ByteString.IOVec (IOVec(..))
 import Network.Socket.ByteString.MsgHdr (MsgHdr(..))
 
-#else
-import GHC.IO.FD
 #endif
 
-#if !defined(mingw32_HOST_OS)
-foreign import CALLCONV unsafe "send"
-  c_send :: CInt -> Ptr a -> CSize -> CInt -> IO CInt
-foreign import CALLCONV unsafe "recv"
-  c_recv :: CInt -> Ptr CChar -> CSize -> CInt -> IO CInt
-#endif
-
 -- ----------------------------------------------------------------------------
 -- Sending
 
 -- | Send data to the socket.  The socket must be connected to a
 -- remote socket.  Returns the number of bytes sent. Applications are
 -- responsible for ensuring that all data has been sent.
+--
+-- Sending data to closed socket may lead to undefined behaviour.
 send :: Socket      -- ^ Connected socket
      -> ByteString  -- ^ Data to send
      -> IO Int      -- ^ Number of bytes sent
-send sock@(MkSocket s _ _ _ _) xs =
-    unsafeUseAsCStringLen xs $ \(str, len) ->
-    liftM fromIntegral $
-#if defined(mingw32_HOST_OS)
-        writeRawBufferPtr "Network.Socket.ByteString.send"
-        (FD s 1) (castPtr str) 0 (fromIntegral len)
-#else
-        throwSocketErrorWaitWrite sock "send" $
-        c_send s str (fromIntegral len) 0
-#endif
+send sock xs = unsafeUseAsCStringLen xs $ \(str, len) ->
+    sendBuf sock (castPtr str) len
 
 -- | Send data to the socket.  The socket must be connected to a
 -- remote socket.  Unlike 'send', this function continues to send data
 -- until either all data has been sent or an error occurs.  On error,
 -- an exception is raised, and there is no way to determine how much
 -- data, if any, was successfully sent.
+--
+-- Sending data to closed socket may lead to undefined behaviour.
 sendAll :: Socket      -- ^ Connected socket
         -> ByteString  -- ^ Data to send
         -> IO ()
@@ -118,6 +101,8 @@
 -- explicitly, so the socket need not be in a connected state.
 -- Returns the number of bytes sent. Applications are responsible for
 -- ensuring that all data has been sent.
+--
+-- Sending data to closed socket may lead to undefined behaviour.
 sendTo :: Socket      -- ^ Socket
        -> ByteString  -- ^ Data to send
        -> SockAddr    -- ^ Recipient address
@@ -131,6 +116,8 @@
 -- data has been sent or an error occurs.  On error, an exception is
 -- raised, and there is no way to determine how much data, if any, was
 -- successfully sent.
+--
+-- Sending data to closed socket may lead to undefined behaviour.
 sendAllTo :: Socket      -- ^ Socket
           -> ByteString  -- ^ Data to send
           -> SockAddr    -- ^ Recipient address
@@ -167,6 +154,8 @@
 -- sent or an error occurs.  On error, an exception is raised, and
 -- there is no way to determine how much data, if any, was
 -- successfully sent.
+--
+-- Sending data to closed socket may lead to undefined behaviour.
 sendMany :: Socket        -- ^ Connected socket
          -> [ByteString]  -- ^ Data to send
          -> IO ()
@@ -190,6 +179,8 @@
 -- continues to send data until either all data has been sent or an
 -- error occurs.  On error, an exception is raised, and there is no
 -- way to determine how much data, if any, was successfully sent.
+--
+-- Sending data to closed socket may lead to undefined behaviour.
 sendManyTo :: Socket        -- ^ Socket
            -> [ByteString]  -- ^ Data to send
            -> SockAddr      -- ^ Recipient address
@@ -226,29 +217,22 @@
 --
 -- For TCP sockets, a zero length return value means the peer has
 -- closed its half side of the connection.
+--
+-- Receiving data from closed socket may lead to undefined behaviour.
 recv :: Socket         -- ^ Connected socket
      -> Int            -- ^ Maximum number of bytes to receive
      -> IO ByteString  -- ^ Data received
 recv sock nbytes
     | nbytes < 0 = ioError (mkInvalidRecvArgError "Network.Socket.ByteString.recv")
-    | otherwise  = createAndTrim nbytes $ recvInner sock nbytes
-
-recvInner :: Socket -> Int -> Ptr Word8 -> IO Int
-recvInner sock nbytes ptr =
-    fmap fromIntegral $
-#if defined(mingw32_HOST_OS)
-        readRawBufferPtr "Network.Socket.ByteString.recv" (FD s 1) ptr 0 (fromIntegral nbytes)
-#else
-        throwSocketErrorWaitRead sock "recv" $
-        c_recv s (castPtr ptr) (fromIntegral nbytes) 0
-#endif
-  where
-    s = sockFd sock
+    | otherwise  = createAndTrim nbytes $ \ptr ->
+        recvBuf sock ptr nbytes
 
 -- | Receive data from the socket.  The socket need not be in a
 -- connected state.  Returns @(bytes, address)@ where @bytes@ is a
 -- 'ByteString' representing the data received and @address@ is a
 -- 'SockAddr' representing the address of the sending socket.
+--
+-- Receiving data from closed socket may lead to undefined behaviour.
 recvFrom :: Socket                     -- ^ Socket
          -> Int                        -- ^ Maximum number of bytes to receive
          -> IO (ByteString, SockAddr)  -- ^ Data received and sender address
@@ -318,12 +302,12 @@
 -- >                     Nothing (Just "3000")
 -- >        let serveraddr = head addrinfos
 -- >        sock <- socket (addrFamily serveraddr) Stream defaultProtocol
--- >        bindSocket sock (addrAddress serveraddr)
+-- >        bind sock (addrAddress serveraddr)
 -- >        listen sock 1
 -- >        (conn, _) <- accept sock
 -- >        talk conn
--- >        sClose conn
--- >        sClose sock
+-- >        close conn
+-- >        close sock
 -- >
 -- >     where
 -- >       talk :: Socket -> IO ()
@@ -346,6 +330,6 @@
 -- >        connect sock (addrAddress serveraddr)
 -- >        sendAll sock $ C.pack "Hello, world!"
 -- >        msg <- recv sock 1024
--- >        sClose sock
+-- >        close sock
 -- >        putStr "Received "
 -- >        C.putStrLn msg
diff --git a/Network/Socket/ByteString/Lazy.hs b/Network/Socket/ByteString/Lazy.hs
--- a/Network/Socket/ByteString/Lazy.hs
+++ b/Network/Socket/ByteString/Lazy.hs
@@ -77,6 +77,8 @@
 -- until a message arrives.
 --
 -- If there is no more data to be received, returns an empty 'ByteString'.
+--
+-- Receiving data from closed socket may lead to undefined behaviour.
 recv :: Socket         -- ^ Connected socket
      -> Int64          -- ^ Maximum number of bytes to receive
      -> IO ByteString  -- ^ Data received
diff --git a/Network/Socket/Internal.hsc b/Network/Socket/Internal.hsc
--- a/Network/Socket/Internal.hsc
+++ b/Network/Socket/Internal.hsc
@@ -43,7 +43,7 @@
     , Family(..)
 
     -- * Socket error functions
-#if defined(HAVE_WINSOCK2_H) && !defined(cygwin32_HOST_OS)
+#if defined(HAVE_WINSOCK2_H)
     , c_getLastError
 #endif
     , throwSocketError
@@ -72,12 +72,14 @@
 import Foreign.C.Error (throwErrno, throwErrnoIfMinus1Retry,
                         throwErrnoIfMinus1RetryMayBlock, throwErrnoIfMinus1_,
                         Errno(..), errnoToIOError)
+#if defined(HAVE_WINSOCK2_H)
 import Foreign.C.String (peekCString)
-import Foreign.C.Types (CInt(..))
 import Foreign.Ptr (Ptr)
+#endif
+import Foreign.C.Types (CInt(..))
 import GHC.Conc (threadWaitRead, threadWaitWrite)
 
-#if defined(HAVE_WINSOCK2_H) && !defined(cygwin32_HOST_OS)
+#if defined(HAVE_WINSOCK2_H)
 import Control.Exception ( evaluate )
 import System.IO.Unsafe ( unsafePerformIO )
 import Control.Monad ( when )
@@ -154,7 +156,7 @@
 {-# SPECIALIZE throwSocketErrorIfMinus1RetryMayBlock
         :: String -> IO b -> IO CInt -> IO CInt #-}
 
-#if (!defined(HAVE_WINSOCK2_H) || defined(cygwin32_HOST_OS))
+#if (!defined(HAVE_WINSOCK2_H))
 
 throwSocketErrorIfMinus1RetryMayBlock name on_block act =
     throwErrnoIfMinus1RetryMayBlock name act on_block
@@ -177,7 +179,7 @@
   throwSocketErrorIfMinus1Retry name act
   return ()
 
-# if defined(HAVE_WINSOCK2_H) && !defined(cygwin32_HOST_OS)
+# if defined(HAVE_WINSOCK2_H)
 throwSocketErrorIfMinus1Retry name act = do
   r <- act
   if (r == -1)
diff --git a/Network/Socket/Types.hsc b/Network/Socket/Types.hsc
--- a/Network/Socket/Types.hsc
+++ b/Network/Socket/Types.hsc
@@ -34,8 +34,12 @@
     , SockAddr(..)
     , isSupportedSockAddr
     , HostAddress
+    , hostAddressToTuple
+    , tupleToHostAddress
 #if defined(IPV6_SOCKET_SUPPORT)
     , HostAddress6
+    , hostAddress6ToTuple
+    , tupleToHostAddress6
     , FlowInfo
     , ScopeID
 #endif
@@ -55,6 +59,7 @@
     ) where
 
 import Control.Concurrent.MVar
+import Control.Exception (throwIO)
 import Control.Monad
 import Data.Bits
 import Data.Maybe
@@ -729,6 +734,11 @@
 -- @PortNumber@ value with the correct network-byte-ordering. You
 -- should not use the PortNum constructor. It will be removed in the
 -- next release.
+--
+-- >>> 1 :: PortNumber
+-- 1
+-- >>> read "1" :: PortNumber
+-- 1
 newtype PortNumber = PortNum Word16 deriving (Eq, Ord, Typeable)
 -- newtyped to prevent accidental use of sane-looking
 -- port numbers that haven't actually been converted to
@@ -739,6 +749,9 @@
 instance Show PortNumber where
   showsPrec p pn = showsPrec p (portNumberToInt pn)
 
+instance Read PortNumber where
+  readsPrec n = map (\(x,y) -> (intToPortNumber x, y)) . readsPrec n
+
 intToPortNumber :: Int -> PortNumber
 intToPortNumber v = PortNum (htons (fromIntegral v))
 
@@ -747,7 +760,8 @@
 
 foreign import CALLCONV unsafe "ntohs" ntohs :: Word16 -> Word16
 foreign import CALLCONV unsafe "htons" htons :: Word16 -> Word16
---foreign import CALLCONV unsafe "ntohl" ntohl :: Word32 -> Word32
+foreign import CALLCONV unsafe "ntohl" ntohl :: Word32 -> Word32
+foreign import CALLCONV unsafe "htonl" htonl :: Word32 -> Word32
 
 instance Enum PortNumber where
     toEnum   = intToPortNumber
@@ -834,9 +848,12 @@
 #if defined(CAN_SOCKET_SUPPORT)
   SockAddrCan{} -> True
 #endif
+#if !(defined(IPV6_SOCKET_SUPPORT) \
+      && defined(DOMAIN_SOCKET_SUPPORT) && defined(CAN_SOCKET_SUPPORT))
   _ -> False
+#endif
 
-#if defined(WITH_WINSOCK) || defined(cygwin32_HOST_OS)
+#if defined(WITH_WINSOCK)
 type CSaFamily = (#type unsigned short)
 #elif defined(darwin_HOST_OS)
 type CSaFamily = (#type u_char)
@@ -875,6 +892,8 @@
 #if defined(CAN_SOCKET_SUPPORT)
 sizeOfSockAddrByFamily AF_CAN   = #const sizeof(struct sockaddr_can)
 #endif
+sizeOfSockAddrByFamily family =
+    error $ "sizeOfSockAddrByFamily: " ++ show family ++ " not supported."
 
 -- | Use a 'SockAddr' with a function requiring a pointer to a
 -- 'SockAddr' and the length of that 'SockAddr'.
@@ -933,7 +952,7 @@
     (#poke struct sockaddr_in6, sin6_family) p ((#const AF_INET6) :: CSaFamily)
     (#poke struct sockaddr_in6, sin6_port) p port
     (#poke struct sockaddr_in6, sin6_flowinfo) p flow
-    (#poke struct sockaddr_in6, sin6_addr) p addr
+    (#poke struct sockaddr_in6, sin6_addr) p (In6Addr addr)
     (#poke struct sockaddr_in6, sin6_scope_id) p scope
 #endif
 #if defined(CAN_SOCKET_SUPPORT)
@@ -962,7 +981,7 @@
     (#const AF_INET6) -> do
         port <- (#peek struct sockaddr_in6, sin6_port) p
         flow <- (#peek struct sockaddr_in6, sin6_flowinfo) p
-        addr <- (#peek struct sockaddr_in6, sin6_addr) p
+        In6Addr addr <- (#peek struct sockaddr_in6, sin6_addr) p
         scope <- (#peek struct sockaddr_in6, sin6_scope_id) p
         return (SockAddrInet6 (PortNum port) flow addr scope)
 #endif
@@ -971,16 +990,56 @@
         ifidx <- (#peek struct sockaddr_can, can_ifindex) p
         return (SockAddrCan ifidx)
 #endif
+    _ -> throwIO $ userError $ "peekSockAddr: " ++ show family ++ " not supported on this platform."
 
 ------------------------------------------------------------------------
 
--- | Network byte order.
+-- | The raw network byte order number is read using host byte order.
+-- Therefore on little-endian architectures the byte order is swapped. For
+-- example @127.0.0.1@ is represented as @0x0100007f@ on little-endian hosts
+-- and as @0x7f000001@ on big-endian hosts.
+--
+-- For direct manipulation prefer 'hostAddressToTuple' and
+-- 'tupleToHostAddress'.
 type HostAddress = Word32
 
+-- | Converts 'HostAddress' to representation-independent IPv4 quadruple.
+-- For example for @127.0.0.1@ the function will return @(0x7f, 0, 0, 1)@
+-- regardless of host endianness.
+hostAddressToTuple :: HostAddress -> (Word8, Word8, Word8, Word8)
+hostAddressToTuple ha' =
+    let ha = htonl ha'
+        byte i = fromIntegral (ha `shiftR` i) :: Word8
+    in (byte 24, byte 16, byte 8, byte 0)
+
+-- | Converts IPv4 quadruple to 'HostAddress'.
+tupleToHostAddress :: (Word8, Word8, Word8, Word8) -> HostAddress
+tupleToHostAddress (b3, b2, b1, b0) =
+    let x `sl` i = fromIntegral x `shiftL` i :: Word32
+    in ntohl $ (b3 `sl` 24) .|. (b2 `sl` 16) .|. (b1 `sl` 8) .|. (b0 `sl` 0)
+
 #if defined(IPV6_SOCKET_SUPPORT)
--- | Host byte order.
+-- | Independent of endianness. For example @::1@ is stored as @(0, 0, 0, 1)@.
+--
+-- For direct manipulation prefer 'hostAddress6ToTuple' and
+-- 'tupleToHostAddress6'.
 type HostAddress6 = (Word32, Word32, Word32, Word32)
 
+hostAddress6ToTuple :: HostAddress6 -> (Word16, Word16, Word16, Word16,
+                                        Word16, Word16, Word16, Word16)
+hostAddress6ToTuple (w3, w2, w1, w0) =
+    let high, low :: Word32 -> Word16
+        high w = fromIntegral (w `shiftR` 16)
+        low w = fromIntegral w
+    in (high w3, low w3, high w2, low w2, high w1, low w1, high w0, low w0)
+
+tupleToHostAddress6 :: (Word16, Word16, Word16, Word16,
+                        Word16, Word16, Word16, Word16) -> HostAddress6
+tupleToHostAddress6 (w7, w6, w5, w4, w3, w2, w1, w0) =
+    let add :: Word16 -> Word16 -> Word32
+        high `add` low = (fromIntegral high `shiftL` 16) .|. (fromIntegral low)
+    in (w7 `add` w6, w5 `add` w4, w3 `add` w2, w1 `add` w0)
+
 -- The peek32 and poke32 functions work around the fact that the RFCs
 -- don't require 32-bit-wide address fields to be present.  We can
 -- only portably rely on an 8-bit field, s6_addr.
@@ -1009,18 +1068,25 @@
     pokeByte 2 (a `sr`  8)
     pokeByte 3 (a `sr`  0)
 
-instance Storable HostAddress6 where
-    sizeOf _    = (#const sizeof(struct in6_addr))
-    alignment _ = alignment (undefined :: CInt)
+-- | Private newtype proxy for the Storable instance. To avoid orphan instances.
+newtype In6Addr = In6Addr HostAddress6
 
+#if __GLASGOW_HASKELL__ < 800
+#let alignment t = "%lu", (unsigned long)offsetof(struct {char x__; t (y__); }, y__)
+#endif
+
+instance Storable In6Addr where
+    sizeOf _    = #const sizeof(struct in6_addr)
+    alignment _ = #alignment struct in6_addr
+
     peek p = do
         a <- peek32 p 0
         b <- peek32 p 1
         c <- peek32 p 2
         d <- peek32 p 3
-        return (a, b, c, d)
+        return $ In6Addr (a, b, c, d)
 
-    poke p (a, b, c, d) = do
+    poke p (In6Addr (a, b, c, d)) = do
         poke32 p 0 a
         poke32 p 1 b
         poke32 p 2 c
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -1,4 +1,6 @@
-# [`network`](http://hackage.haskell.org/package/network) [![Build Status](https://travis-ci.org/haskell/network.svg?branch=master)](https://travis-ci.org/haskell/network)
+# [`network`](http://hackage.haskell.org/package/network) [![Build Status](https://travis-ci.org/haskell/network.svg?branch=master)](https://travis-ci.org/haskell/network) [![Build status](https://ci.appveyor.com/api/projects/status/5erq63o4m29bhl57/branch/master?svg=true)](https://ci.appveyor.com/project/eborden/network/branch/master)
+
+
 
 To build this package using Cabal directly from git, you must run
 `autoreconf` before the usual Cabal build steps
diff --git a/cbits/asyncAccept.c b/cbits/asyncAccept.c
--- a/cbits/asyncAccept.c
+++ b/cbits/asyncAccept.c
@@ -5,7 +5,7 @@
 #include "HsNet.h"
 #include "HsFFI.h"
 
-#if defined(HAVE_WINSOCK2_H) && !defined(__CYGWIN__)
+#if defined(HAVE_WINSOCK2_H)
 
 /* all the way to the end */
 
diff --git a/cbits/initWinSock.c b/cbits/initWinSock.c
--- a/cbits/initWinSock.c
+++ b/cbits/initWinSock.c
@@ -1,7 +1,7 @@
 #include "HsNet.h"
 #include "HsFFI.h"
 
-#if defined(HAVE_WINSOCK2_H) && !defined(__CYGWIN__)
+#if defined(HAVE_WINSOCK2_H)
 
 static int winsock_inited = 0;
 
diff --git a/cbits/winSockErr.c b/cbits/winSockErr.c
--- a/cbits/winSockErr.c
+++ b/cbits/winSockErr.c
@@ -1,7 +1,7 @@
 #include "HsNet.h"
 #include "HsFFI.h"
 
-#if defined(HAVE_WINSOCK2_H) && !defined(__CYGWIN__)
+#if defined(HAVE_WINSOCK2_H)
 #include <stdio.h>
 
 /* to the end */
diff --git a/configure b/configure
--- a/configure
+++ b/configure
@@ -665,6 +665,7 @@
 docdir
 oldincludedir
 includedir
+runstatedir
 localstatedir
 sharedstatedir
 sysconfdir
@@ -736,6 +737,7 @@
 sysconfdir='${prefix}/etc'
 sharedstatedir='${prefix}/com'
 localstatedir='${prefix}/var'
+runstatedir='${localstatedir}/run'
 includedir='${prefix}/include'
 oldincludedir='/usr/include'
 docdir='${datarootdir}/doc/${PACKAGE_TARNAME}'
@@ -988,6 +990,15 @@
   | -silent | --silent | --silen | --sile | --sil)
     silent=yes ;;
 
+  -runstatedir | --runstatedir | --runstatedi | --runstated \
+  | --runstate | --runstat | --runsta | --runst | --runs \
+  | --run | --ru | --r)
+    ac_prev=runstatedir ;;
+  -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \
+  | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \
+  | --run=* | --ru=* | --r=*)
+    runstatedir=$ac_optarg ;;
+
   -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
     ac_prev=sbindir ;;
   -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
@@ -1125,7 +1136,7 @@
 for ac_var in	exec_prefix prefix bindir sbindir libexecdir datarootdir \
 		datadir sysconfdir sharedstatedir localstatedir includedir \
 		oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
-		libdir localedir mandir
+		libdir localedir mandir runstatedir
 do
   eval ac_val=\$$ac_var
   # Remove trailing slashes.
@@ -1278,6 +1289,7 @@
   --sysconfdir=DIR        read-only single-machine data [PREFIX/etc]
   --sharedstatedir=DIR    modifiable architecture-independent data [PREFIX/com]
   --localstatedir=DIR     modifiable single-machine data [PREFIX/var]
+  --runstatedir=DIR       modifiable per-process data [LOCALSTATEDIR/run]
   --libdir=DIR            object code libraries [EPREFIX/lib]
   --includedir=DIR        C header files [PREFIX/include]
   --oldincludedir=DIR     C header files for non-gcc [/usr/include]
diff --git a/examples/EchoClient.hs b/examples/EchoClient.hs
--- a/examples/EchoClient.hs
+++ b/examples/EchoClient.hs
@@ -13,6 +13,6 @@
        connect sock (addrAddress serveraddr)
        sendAll sock $ C.pack "Hello, world!"
        msg <- recv sock 1024
-       sClose sock
+       close sock
        putStr "Received "
        C.putStrLn msg
diff --git a/examples/EchoServer.hs b/examples/EchoServer.hs
--- a/examples/EchoServer.hs
+++ b/examples/EchoServer.hs
@@ -13,12 +13,12 @@
                     Nothing (Just "3000")
        let serveraddr = head addrinfos
        sock <- socket (addrFamily serveraddr) Stream defaultProtocol
-       bindSocket sock (addrAddress serveraddr)
+       bind sock (addrAddress serveraddr)
        listen sock 1
        (conn, _) <- accept sock
        talk conn
-       sClose conn
-       sClose sock
+       close conn
+       close sock
 
     where
       talk :: Socket -> IO ()
diff --git a/include/HsNet.h b/include/HsNet.h
--- a/include/HsNet.h
+++ b/include/HsNet.h
@@ -36,7 +36,7 @@
 # undef IPV6_SOCKET_SUPPORT
 #endif
 
-#if defined(HAVE_WINSOCK2_H) && !defined(__CYGWIN__)
+#if defined(HAVE_WINSOCK2_H)
 #include <winsock2.h>
 # ifdef HAVE_WS2TCPIP_H
 #  include <ws2tcpip.h>
@@ -115,7 +115,7 @@
 extern int
 recvFd(int sock);
 
-#endif /* HAVE_WINSOCK2_H && !__CYGWIN */
+#endif /* HAVE_WINSOCK2_H */
 
 INLINE char *
 my_inet_ntoa(
@@ -138,7 +138,7 @@
 #ifdef HAVE_GETADDRINFO
 INLINE int
 hsnet_getnameinfo(const struct sockaddr* a,socklen_t b, char* c,
-# if defined(HAVE_WINSOCK2_H) && !defined(__CYGWIN__)
+# if defined(HAVE_WINSOCK2_H)
                   DWORD d, char* e, DWORD f, int g)
 # else
                   socklen_t d, char* e, socklen_t f, int g)
@@ -161,7 +161,7 @@
 }
 #endif
 
-#if defined(HAVE_WINSOCK2_H) && !defined(cygwin32_HOST_OS)
+#if defined(HAVE_WINSOCK2_H)
 # define WITH_WINSOCK  1
 #endif
 
diff --git a/include/HsNetworkConfig.h b/include/HsNetworkConfig.h
--- a/include/HsNetworkConfig.h
+++ b/include/HsNetworkConfig.h
@@ -2,13 +2,13 @@
 /* include/HsNetworkConfig.h.in.  Generated from configure.ac by autoheader.  */
 
 /* Define to 1 if you have the `accept4' function. */
-/* #undef HAVE_ACCEPT4 */
+#define HAVE_ACCEPT4 1
 
 /* Define to 1 if you have the <arpa/inet.h> header file. */
 #define HAVE_ARPA_INET_H 1
 
 /* Define to 1 if you have a BSDish sendfile(2) implementation. */
-#define HAVE_BSD_SENDFILE 1
+/* #undef HAVE_BSD_SENDFILE */
 
 /* Define to 1 if you have the declaration of `AI_ADDRCONFIG', and to 0 if you
    don't. */
@@ -55,7 +55,7 @@
 #define HAVE_GETHOSTENT 1
 
 /* Define to 1 if you have getpeereid. */
-#define HAVE_GETPEEREID 1
+/* #undef HAVE_GETPEEREID */
 
 /* Define to 1 if you have the `if_nametoindex' function. */
 #define HAVE_IF_NAMETOINDEX 1
@@ -73,11 +73,14 @@
 #define HAVE_LIMITS_H 1
 
 /* Define to 1 if you have the <linux/can.h> header file. */
-/* #undef HAVE_LINUX_CAN_H */
+#define HAVE_LINUX_CAN_H 1
 
 /* Define to 1 if you have a Linux sendfile(2) implementation. */
-/* #undef HAVE_LINUX_SENDFILE */
+#define HAVE_LINUX_SENDFILE 1
 
+/* Define to 1 if you have the <linux/tcp.h> header file. */
+#define HAVE_LINUX_TCP_H 1
+
 /* Define to 1 if you have the <memory.h> header file. */
 #define HAVE_MEMORY_H 1
 
@@ -115,10 +118,10 @@
 #define HAVE_STRUCT_MSGHDR_MSG_CONTROL 1
 
 /* Define to 1 if `sa_len' is a member of `struct sockaddr'. */
-#define HAVE_STRUCT_SOCKADDR_SA_LEN 1
+/* #undef HAVE_STRUCT_SOCKADDR_SA_LEN */
 
 /* Define to 1 if you have both SO_PEERCRED and struct ucred. */
-/* #undef HAVE_STRUCT_UCRED */
+#define HAVE_STRUCT_UCRED 1
 
 /* Define to 1 if you have the `symlink' function. */
 #define HAVE_SYMLINK 1
diff --git a/network.cabal b/network.cabal
--- a/network.cabal
+++ b/network.cabal
@@ -1,8 +1,8 @@
 name:           network
-version:        2.6.2.1
+version:        2.6.3.0
 license:        BSD3
 license-file:   LICENSE
-maintainer:     Johan Tibell <johan.tibell@gmail.com>
+maintainer:     Kazu Yamamoto, Evan Borden
 synopsis:       Low-level networking interface
 description:
   This package provides a low-level networking interface.
@@ -41,6 +41,7 @@
   cbits/winSockErr.c
 homepage:       https://github.com/haskell/network
 bug-reports:    https://github.com/haskell/network/issues
+tested-with:   GHC == 7.0.4, GHC == 7.4.2, GHC == 7.6.3, GHC == 7.8.4, GHC == 7.10.1, GHC == 7.10.2, GHC == 8.0.1
 
 library
   exposed-modules:
@@ -104,6 +105,17 @@
     network,
     test-framework,
     test-framework-hunit
+  -- Some of the bugs only occur in the threaded RTS
+  ghc-options: -Wall -threaded
+
+test-suite doctest
+  hs-source-dirs: tests
+  main-is: doctests.hs
+  type: exitcode-stdio-1.0
+
+  build-depends:
+    base < 5,
+    doctest >= 0.10.1
 
   ghc-options: -Wall
 
diff --git a/tests/Regression.hs b/tests/Regression.hs
--- a/tests/Regression.hs
+++ b/tests/Regression.hs
@@ -2,8 +2,13 @@
 module Main where
 
 import Network.Socket
+import qualified Network.Socket.ByteString as BS
+
+import Control.Exception
+
 import Test.Framework (Test, defaultMain)
 import Test.Framework.Providers.HUnit (testCase)
+import Test.HUnit (assertFailure)
 
 ------------------------------------------------------------------------
 -- Tests
@@ -16,12 +21,35 @@
     _ <- getAddrInfo (Just hints) (Just "localhost") Nothing
     return ()
 
+mkBadSocketAndTry :: (Socket -> IO a) -> IO (Either IOException a)
+mkBadSocketAndTry f = do
+    sock <- socket AF_INET Stream defaultProtocol
+    try $ f sock
+
+-- Because of 64/32 bitness issues, -1 wasn't correctly checked for on Windows.
+-- See also GHC ticket #12010
+badRecvShouldThrow :: IO ()
+badRecvShouldThrow = do
+    res <- mkBadSocketAndTry $ flip recv 1024
+    case res of
+        Left _ex -> return ()
+        Right _  -> assertFailure "recv didn't throw an exception"
+
+badSendShouldThrow :: IO ()
+badSendShouldThrow = do
+    res <- mkBadSocketAndTry $ flip send "hello"
+    case res of
+        Left _ex -> return ()
+        Right _  -> assertFailure "send didn't throw an exception"
+
 ------------------------------------------------------------------------
 -- List of all tests
 
 tests :: [Test]
 tests =
-    [ testCase "testGetAddrInfo" testGetAddrInfo
+    [ testCase "testGetAddrInfo" testGetAddrInfo,
+      testCase "badRecvShouldThrow" badRecvShouldThrow,
+      testCase "badSendShouldThrow" badSendShouldThrow
     ]
 
 ------------------------------------------------------------------------
diff --git a/tests/Simple.hs b/tests/Simple.hs
--- a/tests/Simple.hs
+++ b/tests/Simple.hs
@@ -5,10 +5,12 @@
 import Control.Concurrent (ThreadId, forkIO, myThreadId)
 import Control.Concurrent.MVar (newEmptyMVar, putMVar, takeMVar, readMVar)
 import qualified Control.Exception as E
-import Control.Monad (liftM, when)
+import Control.Monad
 import qualified Data.ByteString as S
 import qualified Data.ByteString.Char8 as C
+#if defined(HAVE_LINUX_CAN_H)
 import Data.Maybe (fromJust)
+#endif
 import Network.Socket hiding (recv, recvFrom, send, sendTo)
 import Network.Socket.ByteString
 
@@ -137,7 +139,7 @@
       getSocketOption sock UserTimeout >>= (@=?) 1000
       setSocketOption sock UserTimeout 2000
       getSocketOption sock UserTimeout >>= (@=?) 2000
-      sClose sock
+      close sock
 
 {-
 testGetPeerCred:: Assertion
@@ -146,22 +148,22 @@
   where
     clientSetup = do
         sock <- socket AF_UNIX Stream defaultProtocol
-        connect sock $ SockAddrUnix addr 
+        connect sock $ SockAddrUnix addr
         return sock
 
     serverSetup = do
         sock <- socket AF_UNIX Stream defaultProtocol
-        bindSocket sock $ SockAddrUnix addr 
+        bind sock $ SockAddrUnix addr 
         listen sock 1
         return sock
 
     server sock = do
         (clientSock, _) <- accept sock
-        serverAct clientSock
-        sClose clientSock
+        _ <- serverAct clientSock
+        close clientSock
 
     addr = "/tmp/testAddr1"
-    clientAct sock = withSocketsDo $ do  
+    clientAct sock = withSocketsDo $ do
                      sendAll sock testMsg
                      (pid,uid,gid) <- getPeerCred sock
                      putStrLn $ unwords ["pid=",show pid,"uid=",show uid, "gid=", show gid]
@@ -171,27 +173,27 @@
 
 
 testGetPeerEid :: Assertion
-testGetPeerEid =  
+testGetPeerEid =
     test clientSetup clientAct serverSetup server
   where
     clientSetup = do
         sock <- socket AF_UNIX Stream defaultProtocol
-        connect sock $ SockAddrUnix addr 
+        connect sock $ SockAddrUnix addr
         return sock
 
     serverSetup = do
         sock <- socket AF_UNIX Stream defaultProtocol
-        bindSocket sock $ SockAddrUnix addr 
+        bind sock $ SockAddrUnix addr 
         listen sock 1
         return sock
 
     server sock = do
         (clientSock, _) <- accept sock
-        serverAct clientSock
-        sClose clientSock
+        _ <- serverAct clientSock
+        close clientSock
 
     addr = "/tmp/testAddr2"
-    clientAct sock = withSocketsDo $ do  
+    clientAct sock = withSocketsDo $ do
                      sendAll sock testMsg
                      (uid,gid) <- getPeerEid sock
                      putStrLn $ unwords ["uid=",show uid, "gid=", show gid]
@@ -223,11 +225,46 @@
       -- bind the socket to the interface
       bind sock (SockAddrCan $ fromIntegral $ ifIndex)
       return sock
-    
+
     serverSetup = clientSetup
 #endif
 
 ------------------------------------------------------------------------
+-- Conversions of IP addresses
+
+testHostAddressToTuple :: Assertion
+testHostAddressToTuple = do
+    -- Look up a numeric IPv4 host
+    let hints = defaultHints { addrFlags = [AI_NUMERICHOST, AI_ADDRCONFIG] }
+    (AddrInfo{addrAddress = (SockAddrInet _ hostAddr)} : _) <-
+        getAddrInfo (Just hints) (Just "127.128.129.130") Nothing
+    -- and check that the decoded address matches the expected representation
+    (0x7f, 0x80, 0x81, 0x82) @=? hostAddressToTuple hostAddr
+
+testHostAddressToTupleInv :: Assertion
+testHostAddressToTupleInv = do
+    let addr = (0x7f, 0x80, 0x81, 0x82)
+    addr @=? (hostAddressToTuple . tupleToHostAddress) addr
+
+#if defined(IPV6_SOCKET_SUPPORT)
+testHostAddress6ToTuple :: Assertion
+testHostAddress6ToTuple = do
+    -- Look up a numeric IPv6 host
+    let hints = defaultHints { addrFlags = [AI_NUMERICHOST, AI_ADDRCONFIG] }
+        host = "2001:0db8:85a3:0000:0000:8a2e:0370:7334"
+    (AddrInfo{addrAddress = (SockAddrInet6 _ _ hostAddr _)} : _) <-
+        getAddrInfo (Just hints) (Just host) Nothing
+    -- and check that the decoded address matches the expected representation
+    (0x2001, 0x0db8, 0x85a3, 0x0000, 0x0000, 0x8a2e, 0x0370, 0x7334)
+        @=? hostAddress6ToTuple hostAddr
+
+testHostAddress6ToTupleInv :: Assertion
+testHostAddress6ToTupleInv = do
+    let addr = (0x2001, 0x0db8, 0x85a3, 0x0000, 0x0000, 0x8a2e, 0x0370, 0x7334)
+    addr @=? (hostAddress6ToTuple . tupleToHostAddress6) addr
+#endif
+
+------------------------------------------------------------------------
 -- Other
 
 ------------------------------------------------------------------------
@@ -251,8 +288,16 @@
 --    , testCase "testGetPeerCred" testGetPeerCred
 --    , testCase "testGetPeerEid" testGetPeerEid
 #if defined(HAVE_LINUX_CAN_H)
-    , testCase "testCanSend" testCanSend  
+    , testCase "testCanSend" testCanSend
 #endif
+      -- conversions of IP addresses
+    , testCase "testHostAddressToTuple" testHostAddressToTuple
+    , testCase "testHostAddressToTupleInv" testHostAddressToTupleInv
+#if defined(IPV6_SOCKET_SUPPORT)
+    , testCase "testHostAddress6ToTuple" testHostAddress6ToTuple
+    , testCase "testHostAddress6ToTupleInv" testHostAddress6ToTupleInv
+#endif
+      -- other
     ]
 
 tests :: [Test]
@@ -292,7 +337,7 @@
         sock <- socket AF_INET Stream defaultProtocol
         setSocketOption sock ReuseAddr 1
         addr <- inet_addr serverAddr
-        bindSocket sock (SockAddrInet aNY_PORT addr)
+        bind sock (SockAddrInet aNY_PORT addr)
         listen sock 1
         serverPort <- socketPort sock
         putMVar portVar serverPort
@@ -300,8 +345,8 @@
 
     server sock = do
         (clientSock, _) <- accept sock
-        serverAct clientSock
-        sClose clientSock
+        _ <- serverAct clientSock
+        close clientSock
 
 -- | Create an unconnected 'Socket' for sending UDP and receiving
 -- datagrams and then run 'clientAct' and 'serverAct'.
@@ -320,7 +365,7 @@
         sock <- socket AF_INET Datagram defaultProtocol
         setSocketOption sock ReuseAddr 1
         addr <- inet_addr serverAddr
-        bindSocket sock (SockAddrInet aNY_PORT addr)
+        bind sock (SockAddrInet aNY_PORT addr)
         serverPort <- socketPort sock
         putMVar portVar serverPort
         return sock
@@ -332,13 +377,13 @@
 test clientSetup clientAct serverSetup serverAct = do
     tid <- myThreadId
     barrier <- newEmptyMVar
-    forkIO $ server barrier
+    _ <- forkIO $ server barrier
     client tid barrier
   where
     server barrier = do
-        E.bracket serverSetup sClose $ \sock -> do
+        E.bracket serverSetup close $ \sock -> do
             serverReady
-            serverAct sock
+            _ <- serverAct sock
             putMVar barrier ()
       where
         -- | Signal to the client that it can proceed.
@@ -347,8 +392,8 @@
     client tid barrier = do
         takeMVar barrier
         -- Transfer exceptions to the main thread.
-        bracketWithReraise tid clientSetup sClose $ \res -> do
-            clientAct res
+        bracketWithReraise tid clientSetup close $ \res -> do
+            _ <- clientAct res
             takeMVar barrier
 
 -- | Like 'bracket' but catches and reraises the exception in another
diff --git a/tests/doctests.hs b/tests/doctests.hs
new file mode 100644
--- /dev/null
+++ b/tests/doctests.hs
@@ -0,0 +1,20 @@
+import Test.DocTest
+
+main :: IO ()
+main = doctest [
+    "-i"
+  , "-idist/build"
+  , "-i."
+  , "-idist/build/autogen"
+  , "-Idist/build/autogen"
+  , "-Idist/build"
+  , "-Iinclude"
+  , "-optP-include"
+  , "-optPdist/build/autogen/cabal_macros.h"
+  , "-DCALLCONV=ccall"
+  , "-XCPP"
+  , "-XDeriveDataTypeable"
+  , "-package-db dist/package.conf.inplace"
+  , "-package network"
+  , "Network"
+  ]
