packages feed

network 2.6.2.1 → 2.6.3.0

raw patch · 21 files changed

+528/−315 lines, 21 filesdep +doctestdep ~base

Dependencies added: doctest

Dependency ranges changed: base

Files

CHANGELOG.md view
@@ -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.
Network.hs view
@@ -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
Network/BSD.hsc view
@@ -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
Network/Socket.hsc view
@@ -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
Network/Socket/ByteString.hsc view
@@ -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
Network/Socket/ByteString/Lazy.hs view
@@ -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
Network/Socket/Internal.hsc view
@@ -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)
Network/Socket/Types.hsc view
@@ -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
README.md view
@@ -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
cbits/asyncAccept.c view
@@ -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 */ 
cbits/initWinSock.c view
@@ -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; 
cbits/winSockErr.c view
@@ -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 */
configure view
@@ -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]
examples/EchoClient.hs view
@@ -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
examples/EchoServer.hs view
@@ -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 ()
include/HsNet.h view
@@ -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 
include/HsNetworkConfig.h view
@@ -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
network.cabal view
@@ -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 
tests/Regression.hs view
@@ -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     ]  ------------------------------------------------------------------------
tests/Simple.hs view
@@ -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
+ tests/doctests.hs view
@@ -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"+  ]