packages feed

network 2.8.0.1 → 3.0.0.0

raw patch · 51 files changed

+3756/−5449 lines, 51 filesdep +deepseq

Dependencies added: deepseq

Files

CHANGELOG.md view
@@ -1,10 +1,26 @@-## Version 2.8.0.1+## Version 3.0.0.0 -* Eensuring that accept returns a correct sockaddr for unix domain.-  [#400](https://github.com/haskell/network/pull/400)-* Avoid out of bounds writes in pokeSockAddr.-  [#400](https://github.com/haskell/network/pull/400)+* Breaking change: the Network and Network.BSD are removed.+  Network.BSD is provided a new package: network-bsd.+* Breaking change: the signatures are changed:+```+old fdSocket :: Socket -> CInt+new fdSocket :: Socket -> IO CInt +old mkSocket :: CInt -> Family -> SocketType -> ProtocolNumber -> SocketStatus -> IO Socket+new mkSocket :: CInt Socket+```+* Breaking change: the deprecated APIs are removed: send, sendTo, recv, recvFrom, recvLen, htonl, ntohl, inet_addr, int_ntoa, bindSocket, sClose, SocketStatus, isConnected, isBound, isListening, isReadable, isWritable, sIsConnected, sIsBound, sIsListening, sIsReadable, sIsWritable, aNY_PORT, iNADDR_ANY, iN6ADDR_ANY, sOMAXCONN, sOL_SOCKET, sCM_RIGHTS, packSocketType, getPeerCred.+* Breaking chage: SockAddrCan is removed from SockAddr.+* Socket addresses are extendable with Network.Socket.Address.+* "socket" is now asynchronous-exception-safe.+  [#336](https://github.com/haskell/network/pull/336)+* "recvFrom" returns (0, addr) instead of throwing an error on EOF.+  [#360](https://github.com/haskell/network/pull/360)+* All APIs are available on any platforms.+* Build system is simplified.+* Bug fixes.+ ## Version 2.8.0.0  * Breaking change: PortNumber originally contained Word16 in network@@ -51,7 +67,7 @@               aNY_PORT, iNADDR_ANY, iN6ADDR_ANY, sOMAXCONN,               sOL_SOCKET, sCM_RIGHTS,               packFamily, unpackFamily, packSocketType- * Do not closeFd within sendFd.+ * Breaking change: do not closeFd within sendFd.    [#271](https://github.com/haskell/network/pull/271)  * Exporting ifNameToIndex and ifIndexToName from Network.Socket.  * New APIs: setCloseOnExecIfNeeded, getCloseOnExec and getNonBlock@@ -74,10 +90,9 @@ ## Version 2.6.3.3   * Adds a function to show the defaultHints without reading their undefined fields-   [#291](https://github.com/haskell/network/pull/291)+   [#291](https://github.com/haskell/network/pull/292)  * Improve exception error messages for getAddrInfo and getNameInfo    [#289](https://github.com/haskell/network/pull/289)- * Deprecating SockAddrCan.  ## Version 2.6.3.2 @@ -142,15 +157,15 @@  ## Version 2.6.2.1 - * Regenerate configure and HsNetworkConfig.h.in.+ * Regenerate configure and `HsNetworkConfig.h.in`.   * Better detection of CAN sockets.  ## Version 2.6.2.0 - * Add support for TCP_USER_TIMEOUT.+ * Add support for `TCP_USER_TIMEOUT`. - * Don't conditionally export the SockAddr constructors.+ * Don't conditionally export the `SockAddr` constructors. - * Add isSupportSockAddr to allow checking for supported address types+ * Add `isSupportSockAddr` to allow checking for supported address types    at runtime.
− Network.hs
@@ -1,480 +0,0 @@-{-# LANGUAGE CPP #-}-{-# OPTIONS_GHC -fno-warn-warnings-deprecations #-}-{-# OPTIONS_HADDOCK hide #-}--------------------------------------------------------------------------------- |--- Module      :  Network--- Copyright   :  (c) The University of Glasgow 2001--- License     :  BSD-style (see the file libraries/network/LICENSE)------ Maintainer  :  libraries@haskell.org--- Stability   :  provisional--- Portability :  portable------ This module is kept for backwards-compatibility. New users are--- encouraged to use "Network.Socket" instead.------ "Network" was intended as a \"higher-level\" interface to networking--- facilities, and only supports TCP.-----------------------------------------------------------------------------------#include "HsNetworkConfig.h"--#ifdef HAVE_GETADDRINFO--- Use IPv6-capable function definitions if the OS supports it.-#define IPV6_SOCKET_SUPPORT 1-#endif--module Network {-# DEPRECATED "The high level Network interface is no longer supported. Please use Network.Socket." #-}-    (-    -- * Basic data types-      Socket-    , PortID(..)-    , HostName-    , PortNumber--    -- * Initialisation-    , withSocketsDo--    -- * Server-side connections-    , listenOn-    , accept-    , sClose--    -- * Client-side connections-    , connectTo--    -- * Simple sending and receiving-    {-$sendrecv-}-    , sendTo-    , recvFrom--    -- * Miscellaneous-    , socketPort--    -- * Networking Issues-    -- ** Buffering-    {-$buffering-}--    -- ** Improving I\/O Performance over sockets-    {-$performance-}-    ) where--import Control.Monad (liftM)-import Data.Maybe (fromJust)-import Network.BSD-import Network.Socket hiding (accept, socketPort, recvFrom,-                              sendTo, PortNumber, sClose)-import qualified Network.Socket as Socket (accept)-import System.IO-import Prelude-import qualified Control.Exception as Exception---- ------------------------------------------------------------------------------ High Level ``Setup'' functions---- If the @PortID@ specifies a unix family socket and the @Hostname@--- differs from that returned by @getHostname@ then an error is--- raised. Alternatively an empty string may be given to @connectTo@--- signalling that the current hostname applies.--data PortID =-          Service String                -- Service Name eg "ftp"-        | PortNumber PortNumber         -- User defined Port Number-#if !defined(mingw32_HOST_OS)-        | UnixSocket String             -- Unix family socket in file system-#endif-        deriving (Show, Eq)---- | Calling 'connectTo' creates a client side socket which is--- connected to the given host and port.  The Protocol and socket type is--- derived from the given port identifier.  If a port number is given--- then the result is always an internet family 'Stream' socket.--connectTo :: HostName           -- Hostname-          -> PortID             -- Port Identifier-          -> IO Handle          -- Connected Socket--#if defined(IPV6_SOCKET_SUPPORT)--- IPv6 and IPv4.--connectTo hostname (Service serv) = connect' "Network.connectTo" hostname serv--connectTo hostname (PortNumber port) = connect' "Network.connectTo" hostname (show port)-#else--- IPv4 only.--connectTo hostname (Service serv) = do-    proto <- getProtocolNumber "tcp"-    bracketOnError-        (socket AF_INET Stream proto)-        (sClose)  -- only done if there's an error-        (\sock -> do-          port  <- getServicePortNumber serv-          he    <- getHostByName hostname-          connect sock (SockAddrInet port (hostAddress he))-          socketToHandle sock ReadWriteMode-        )--connectTo hostname (PortNumber port) = do-    proto <- getProtocolNumber "tcp"-    bracketOnError-        (socket AF_INET Stream proto)-        (sClose)  -- only done if there's an error-        (\sock -> do-          he <- getHostByName hostname-          connect sock (SockAddrInet port (hostAddress he))-          socketToHandle sock ReadWriteMode-        )-#endif--#if !defined(mingw32_HOST_OS)-connectTo _ (UnixSocket path) = do-    bracketOnError-        (socket AF_UNIX Stream 0)-        (sClose)-        (\sock -> do-          connect sock (SockAddrUnix path)-          socketToHandle sock ReadWriteMode-        )-#endif--#if defined(IPV6_SOCKET_SUPPORT)-connect' :: String -> HostName -> ServiceName -> IO Handle--connect' caller host serv = do-    proto <- getProtocolNumber "tcp"-    let hints = defaultHints { addrFlags = [AI_ADDRCONFIG]-                             , addrProtocol = proto-                             , addrSocketType = Stream }-    addrs <- getAddrInfo (Just hints) (Just host) (Just serv)-    firstSuccessful caller $ map tryToConnect addrs-  where-  tryToConnect addr =-    bracketOnError-        (socket (addrFamily addr) (addrSocketType addr) (addrProtocol addr))-        (sClose)  -- only done if there's an error-        (\sock -> do-          connect sock (addrAddress addr)-          socketToHandle sock ReadWriteMode-        )-#endif---- | Creates the server side socket which has been bound to the--- specified port.------ 'maxListenQueue' (typically 128) is specified to the listen queue.--- This is good enough for normal network servers but is too small--- for high performance servers.------ To avoid the \"Address already in use\" problems,--- the 'ReuseAddr' socket option is set on the listening socket.------ If available, the 'IPv6Only' socket option is set to 0--- so that both IPv4 and IPv6 can be accepted with this socket.------ If you don't like the behavior above, please use the lower level--- 'Network.Socket.listen' instead.--listenOn :: PortID      -- ^ Port Identifier-         -> IO Socket   -- ^ Listening Socket--#if defined(IPV6_SOCKET_SUPPORT)--- IPv6 and IPv4.--listenOn (Service serv) = listen' serv--listenOn (PortNumber port) = listen' (show port)-#else--- IPv4 only.--listenOn (Service serv) = do-    proto <- getProtocolNumber "tcp"-    bracketOnError-        (socket AF_INET Stream proto)-        (sClose)-        (\sock -> do-            port    <- getServicePortNumber serv-            setSocketOption sock ReuseAddr 1-            bind sock (SockAddrInet port iNADDR_ANY)-            listen sock maxListenQueue-            return sock-        )--listenOn (PortNumber port) = do-    proto <- getProtocolNumber "tcp"-    bracketOnError-        (socket AF_INET Stream proto)-        (sClose)-        (\sock -> do-            setSocketOption sock ReuseAddr 1-            bind sock (SockAddrInet port iNADDR_ANY)-            listen sock maxListenQueue-            return sock-        )-#endif--#if !defined(mingw32_HOST_OS)-listenOn (UnixSocket path) =-    bracketOnError-        (socket AF_UNIX Stream 0)-        (sClose)-        (\sock -> do-            setSocketOption sock ReuseAddr 1-            bind sock (SockAddrUnix path)-            listen sock maxListenQueue-            return sock-        )-#endif--#if defined(IPV6_SOCKET_SUPPORT)-listen' :: ServiceName -> IO Socket--listen' serv = do-    proto <- getProtocolNumber "tcp"-    -- We should probably specify addrFamily = AF_INET6 and the filter-    -- code below should be removed. AI_ADDRCONFIG is probably not-    -- necessary. But this code is well-tested. So, let's keep it.-    let hints = defaultHints { addrFlags = [AI_ADDRCONFIG, AI_PASSIVE]-                             , addrSocketType = Stream-                             , addrProtocol = proto }-    addrs <- getAddrInfo (Just hints) Nothing (Just serv)-    -- Choose an IPv6 socket if exists.  This ensures the socket can-    -- handle both IPv4 and IPv6 if v6only is false.-    let addrs' = filter (\x -> addrFamily x == AF_INET6) addrs-        addr = if null addrs' then head addrs else head addrs'-    bracketOnError-        (socket (addrFamily addr) (addrSocketType addr) (addrProtocol addr))-        (sClose)-        (\sock -> do-            setSocketOption sock ReuseAddr 1-            bind sock (addrAddress addr)-            listen sock maxListenQueue-            return sock-        )-#endif---- -------------------------------------------------------------------------------- accept---- | Accept a connection on a socket created by 'listenOn'.  Normal--- I\/O operations (see "System.IO") can be used on the 'Handle'--- returned to communicate with the client.--- Notice that although you can pass any Socket to Network.accept,--- only sockets of either AF_UNIX, AF_INET, or AF_INET6 will work--- (this shouldn't be a problem, though). When using AF_UNIX, HostName--- will be set to the path of the socket and PortNumber to -1.----accept :: Socket                -- ^ Listening Socket-       -> IO (Handle,-              HostName,-              PortNumber)       -- ^ Triple of: read\/write 'Handle' for-                                -- communicating with the client,-                                -- the 'HostName' of the peer socket, and-                                -- the 'PortNumber' of the remote connection.-accept sock@(MkSocket _ AF_INET _ _ _) = do- ~(sock', (SockAddrInet port haddr)) <- Socket.accept sock- peer <- catchIO-          (do-             (HostEntry peer _ _ _) <- getHostByAddr AF_INET haddr-             return peer-          )-          (\_e -> inet_ntoa haddr)-                -- if getHostByName fails, we fall back to the IP address- handle <- socketToHandle sock' ReadWriteMode- return (handle, peer, port)-#if defined(IPV6_SOCKET_SUPPORT)-accept sock@(MkSocket _ AF_INET6 _ _ _) = do- (sock', addr) <- Socket.accept sock- peer <- catchIO ((fromJust . fst) `liftM` getNameInfo [] True False addr) $-         \_ -> case addr of-                 SockAddrInet  _   a   -> inet_ntoa a-                 SockAddrInet6 _ _ a _ -> return (show a)-#if defined(mingw32_HOST_OS)-                 SockAddrUnix {}       -> ioError $ userError "Network.accept: peer socket address 'SockAddrUnix' not supported on this platform."-#else-                 SockAddrUnix      a   -> return a-#endif-#if defined(CAN_SOCKET_SUPPORT)-                 SockAddrCan {}        -> ioError $ userError "Network.accept: peer socket address 'SockAddrCan' not supported."-#else-                 SockAddrCan {}        -> ioError $ userError "Network.accept: peer socket address 'SockAddrCan' not supported on this platform."-#endif- handle <- socketToHandle sock' ReadWriteMode- let port = case addr of-              SockAddrInet  p _     -> p-              SockAddrInet6 p _ _ _ -> p-              _                     -> -1- return (handle, peer, port)-#endif-#if !defined(mingw32_HOST_OS)-accept sock@(MkSocket _ AF_UNIX _ _ _) = do- ~(sock', (SockAddrUnix path)) <- Socket.accept sock- handle <- socketToHandle sock' ReadWriteMode- return (handle, path, -1)-#endif-accept (MkSocket _ family _ _ _) =-  ioError $ userError $ "Network.accept: address family '" ++-    show family ++ "' not supported."----- | 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 deprecated,-               -- hence the re-export would also be marked as such.---- -------------------------------------------------------------------------------- sendTo/recvFrom--{-$sendrecv-Send and receive data from\/to the given host and port number.  These-should normally only be used where the socket will not be required for-further calls. Also, note that due to the use of 'hGetContents' in 'recvFrom'-the socket will remain open (i.e. not available) even if the function already-returned. Their use is strongly discouraged except for small test-applications-or invocations from the command line.--}--sendTo :: HostName      -- Hostname-       -> PortID        -- Port Number-       -> String        -- Message to send-       -> IO ()-sendTo h p msg = do-  s <- connectTo h p-  hPutStr s msg-  hClose s--recvFrom :: HostName    -- Hostname-         -> PortID      -- Port Number-         -> IO String   -- Received Data--#if defined(IPV6_SOCKET_SUPPORT)-recvFrom host port = do-    proto <- getProtocolNumber "tcp"-    let hints = defaultHints { addrFlags = [AI_ADDRCONFIG]-                             , addrProtocol = proto-                             , addrSocketType = Stream }-    allowed <- map addrAddress `liftM` getAddrInfo (Just hints) (Just host)-                                                   Nothing-    s <- listenOn port-    let waiting = do-        (s', addr) <- Socket.accept s-        if not (addr `oneOf` allowed)-         then sClose s' >> waiting-         else socketToHandle s' ReadMode >>= hGetContents-    waiting-  where-    a@(SockAddrInet _ ha) `oneOf` ((SockAddrInet _ hb):bs)-        | ha == hb = True-        | otherwise = a `oneOf` bs-    a@(SockAddrInet6 _ _ ha _) `oneOf` ((SockAddrInet6 _ _ hb _):bs)-        | ha == hb = True-        | otherwise = a `oneOf` bs-    _ `oneOf` _ = False-#else-recvFrom host port = do- ip  <- getHostByName host- let ipHs = hostAddresses ip- s   <- listenOn port- let-  waiting = do-     ~(s', SockAddrInet _ haddr)  <-  Socket.accept s-     he <- getHostByAddr AF_INET haddr-     if not (any (`elem` ipHs) (hostAddresses he))-      then do-         sClose s'-         waiting-      else do-        h <- socketToHandle s' ReadMode-        msg <- hGetContents h-        return msg-- message <- waiting- return message-#endif---- ------------------------------------------------------------------------------ Access function returning the port type/id of socket.---- | Returns the 'PortID' associated with a given socket.-socketPort :: Socket -> IO PortID-socketPort s = do-    sockaddr <- getSocketName s-    case sockaddr of-      SockAddrInet port _      -> return $ PortNumber port-#if defined(IPV6_SOCKET_SUPPORT)-      SockAddrInet6 port _ _ _ -> return $ PortNumber port-#else-      SockAddrInet6 {}         -> ioError $ userError "Network.socketPort: socket address 'SockAddrInet6' not supported on this platform."-#endif-#if defined(mingw32_HOST_OS)-      SockAddrUnix {}          -> ioError $ userError "Network.socketPort: socket address 'SockAddrUnix' not supported on this platform."-#else-      SockAddrUnix path        -> return $ UnixSocket path-#endif-      SockAddrCan {}           -> ioError $ userError "Network.socketPort: socket address 'SockAddrCan' not supported."---- ------------------------------------------------------------------------------ Utils---- Like bracket, but only performs the final action if there was an--- exception raised by the middle bit.-bracketOnError-        :: IO a         -- ^ computation to run first (\"acquire resource\")-        -> (a -> IO b)  -- ^ computation to run last (\"release resource\")-        -> (a -> IO c)  -- ^ computation to run in-between-        -> IO c         -- returns the value from the in-between computation-bracketOnError = Exception.bracketOnError---------------------------------------------------------------------------------- Extra documentation--{-$buffering--The 'Handle' returned by 'connectTo' and 'accept' is 'NoBuffering' by-default.  For an interactive application you may want to set the-buffering mode on the 'Handle' to-'LineBuffering' or 'BlockBuffering', like so:--> h <- connectTo host port-> hSetBuffering h LineBuffering--}--{-$performance--For really fast I\/O, it might be worth looking at the 'hGetBuf' and-'hPutBuf' family of functions in "System.IO".--}--catchIO :: IO a -> (Exception.IOException -> IO a) -> IO a-#if MIN_VERSION_base(4,0,0)-catchIO = Exception.catch-#else-catchIO = Exception.catchJust Exception.ioErrors-#endif---- Version of try implemented in terms of the locally defined catchIO-tryIO :: IO a -> IO (Either Exception.IOException a)-tryIO m = catchIO (liftM Right m) (return . Left)---- Returns the first action from a list which does not throw an exception.--- If all the actions throw exceptions (and the list of actions is not empty),--- the last exception is thrown.--- The operations are run outside of the catchIO cleanup handler because--- catchIO masks asynchronous exceptions in the cleanup handler.--- In the case of complete failure, the last exception is actually thrown.-firstSuccessful :: String -> [IO a] -> IO a-firstSuccessful caller = go Nothing-  where-  -- Attempt the next operation, remember exception on failure-  go _ (p:ps) =-    do r <- tryIO p-       case r of-         Right x -> return x-         Left  e -> go (Just e) ps--  -- All operations failed, throw error if one exists-  go Nothing  [] = ioError $ userError $ caller ++ ": firstSuccessful: empty list"-  go (Just e) [] = Exception.throwIO e
− Network/BSD.hsc
@@ -1,574 +0,0 @@-{-# LANGUAGE CPP, ForeignFunctionInterface #-}-{-# OPTIONS_HADDOCK hide #-}-{-# OPTIONS_GHC -fno-warn-warnings-deprecations #-}--------------------------------------------------------------------------------- |--- Module      :  Network.BSD--- Copyright   :  (c) The University of Glasgow 2001--- License     :  BSD-style (see the file libraries/network/LICENSE)------ Maintainer  :  libraries@haskell.org--- Stability   :  experimental--- Portability :  non-portable------ The "Network.BSD" module defines Haskell bindings to network--- programming functionality provided by BSD Unix derivatives.-----------------------------------------------------------------------------------#include "HsNet.h"-##include "HsNetDef.h"--module Network.BSD  {-# DEPRECATED "This platform dependent module is no longer supported." #-}-    (-    -- * Host names-      HostName-    , getHostName--    , HostEntry(..)-    , getHostByName-    , getHostByAddr-    , hostAddress--#if defined(HAVE_GETHOSTENT) && !defined(mingw32_HOST_OS)-    , getHostEntries--    -- ** Low level functionality-    , setHostEntry-    , getHostEntry-    , endHostEntry-#endif--    -- * Service names-    , ServiceEntry(..)-    , ServiceName-    , getServiceByName-    , getServiceByPort-    , getServicePortNumber--#if !defined(mingw32_HOST_OS)-    , getServiceEntries--    -- ** Low level functionality-    , getServiceEntry-    , setServiceEntry-    , endServiceEntry-#endif--    -- * Protocol names-    , ProtocolName-    , ProtocolNumber-    , ProtocolEntry(..)-    , getProtocolByName-    , getProtocolByNumber-    , getProtocolNumber-    , defaultProtocol--#if !defined(mingw32_HOST_OS)-    , getProtocolEntries-    -- ** Low level functionality-    , setProtocolEntry-    , getProtocolEntry-    , endProtocolEntry-#endif--    -- * Port numbers-    , PortNumber--    -- * Network names-    , NetworkName-    , NetworkAddr-    , NetworkEntry(..)--#if !defined(mingw32_HOST_OS)-    , getNetworkByName-    , getNetworkByAddr-    , getNetworkEntries-    -- ** Low level functionality-    , setNetworkEntry-    , getNetworkEntry-    , endNetworkEntry-#endif--#if defined(HAVE_IF_NAMETOINDEX)-    -- * Interface names-    , ifNameToIndex-#endif--    ) where--import Network.Socket--import Control.Concurrent (MVar, newMVar, withMVar)-import qualified Control.Exception as E-import Foreign.C.String (CString, peekCString, withCString)-#if defined(HAVE_WINSOCK2_H)-import Foreign.C.Types ( CShort )-#endif-import Foreign.C.Types ( CInt(..), CULong(..), CSize(..) )-import Foreign.Ptr (Ptr, nullPtr)-import Foreign.Storable (Storable(..))-import Foreign.Marshal.Array (allocaArray0, peekArray0)-import Foreign.Marshal.Utils (with, fromBool)-import Data.Typeable-import System.IO.Error (ioeSetErrorString, mkIOError)-import System.IO.Unsafe (unsafePerformIO)--import GHC.IO.Exception--import Control.Monad (liftM)--import Network.Socket.Internal (throwSocketErrorIfMinus1_)---- ------------------------------------------------------------------------------ Basic Types--type ProtocolName = String---- ------------------------------------------------------------------------------ Service Database Access---- Calling getServiceByName for a given service and protocol returns--- the systems service entry.  This should be used to find the port--- numbers for standard protocols such as SMTP and FTP.  The remaining--- three functions should be used for browsing the service database--- sequentially.---- Calling setServiceEntry with True indicates that the service--- database should be left open between calls to getServiceEntry.  To--- close the database a call to endServiceEntry is required.  This--- database file is usually stored in the file /etc/services.--data ServiceEntry  =-  ServiceEntry  {-     serviceName     :: ServiceName,    -- Official Name-     serviceAliases  :: [ServiceName],  -- aliases-     servicePort     :: PortNumber,     -- Port Number  ( network byte order )-     serviceProtocol :: ProtocolName    -- Protocol-  } deriving (Show, Typeable)--instance Storable ServiceEntry where-   sizeOf    _ = #const sizeof(struct servent)-   alignment _ = alignment (undefined :: CInt) -- ???--   peek p = do-        s_name    <- (#peek struct servent, s_name) p >>= peekCString-        s_aliases <- (#peek struct servent, s_aliases) p-                           >>= peekArray0 nullPtr-                           >>= mapM peekCString-        s_port    <- (#peek struct servent, s_port) p-        s_proto   <- (#peek struct servent, s_proto) p >>= peekCString-        return (ServiceEntry {-                        serviceName     = s_name,-                        serviceAliases  = s_aliases,-#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     = (fromIntegral (s_port :: CInt)),-#endif-                        serviceProtocol = s_proto-                })--   poke = throwUnsupportedOperationPoke "ServiceEntry"----- | Get service by name.-getServiceByName :: ServiceName         -- Service Name-                 -> ProtocolName        -- Protocol Name-                 -> IO ServiceEntry     -- Service Entry-getServiceByName name proto = withLock $ do- withCString name  $ \ cstr_name  -> do- withCString proto $ \ cstr_proto -> do- throwNoSuchThingIfNull "Network.BSD.getServiceByName" "no such service entry"-   $ c_getservbyname cstr_name cstr_proto- >>= peek--foreign import CALLCONV unsafe "getservbyname"-  c_getservbyname :: CString -> CString -> IO (Ptr ServiceEntry)---- | Get the service given a 'PortNumber' and 'ProtocolName'.-getServiceByPort :: PortNumber -> ProtocolName -> IO ServiceEntry-getServiceByPort port proto = withLock $ do- withCString proto $ \ cstr_proto -> do- throwNoSuchThingIfNull "Network.BSD.getServiceByPort" "no such service entry"-   $ c_getservbyport (fromIntegral port) cstr_proto- >>= peek--foreign import CALLCONV unsafe "getservbyport"-  c_getservbyport :: CInt -> CString -> IO (Ptr ServiceEntry)---- | Get the 'PortNumber' corresponding to the 'ServiceName'.-getServicePortNumber :: ServiceName -> IO PortNumber-getServicePortNumber name = do-    (ServiceEntry _ _ port _) <- getServiceByName name "tcp"-    return port--#if !defined(mingw32_HOST_OS)-getServiceEntry :: IO ServiceEntry-getServiceEntry = withLock $ do- throwNoSuchThingIfNull "Network.BSD.getServiceEntry" "no such service entry"-   $ c_getservent- >>= peek--foreign import ccall unsafe "getservent" c_getservent :: IO (Ptr ServiceEntry)--setServiceEntry :: Bool -> IO ()-setServiceEntry flg = withLock $ c_setservent (fromBool flg)--foreign import ccall unsafe  "setservent" c_setservent :: CInt -> IO ()--endServiceEntry :: IO ()-endServiceEntry = withLock $ c_endservent--foreign import ccall unsafe  "endservent" c_endservent :: IO ()--getServiceEntries :: Bool -> IO [ServiceEntry]-getServiceEntries stayOpen = do-  setServiceEntry stayOpen-  getEntries (getServiceEntry) (endServiceEntry)-#endif---- ------------------------------------------------------------------------------ Protocol Entries---- The following relate directly to the corresponding UNIX C--- calls for returning the protocol entries. The protocol entry is--- represented by the Haskell type ProtocolEntry.---- As for setServiceEntry above, calling setProtocolEntry.--- determines whether or not the protocol database file, usually--- @/etc/protocols@, is to be kept open between calls of--- getProtocolEntry. Similarly,--data ProtocolEntry =-  ProtocolEntry  {-     protoName    :: ProtocolName,      -- Official Name-     protoAliases :: [ProtocolName],    -- aliases-     protoNumber  :: ProtocolNumber     -- Protocol Number-  } deriving (Read, Show, Typeable)--instance Storable ProtocolEntry where-   sizeOf    _ = #const sizeof(struct protoent)-   alignment _ = alignment (undefined :: CInt) -- ???--   peek p = do-        p_name    <- (#peek struct protoent, p_name) p >>= peekCString-        p_aliases <- (#peek struct protoent, p_aliases) p-                           >>= peekArray0 nullPtr-                           >>= mapM peekCString-#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.-        p_proto_short  <- (#peek struct protoent, p_proto) p-        let p_proto = fromIntegral (p_proto_short :: CShort)-#else-        p_proto        <- (#peek struct protoent, p_proto) p-#endif-        return (ProtocolEntry {-                        protoName    = p_name,-                        protoAliases = p_aliases,-                        protoNumber  = p_proto-                })--   poke = throwUnsupportedOperationPoke "ProtocolEntry"---getProtocolByName :: ProtocolName -> IO ProtocolEntry-getProtocolByName name = withLock $ do- withCString name $ \ name_cstr -> do- throwNoSuchThingIfNull "Network.BSD.getProtocolByName" ("no such protocol name: " ++ name)-   $ c_getprotobyname name_cstr- >>= peek--foreign import  CALLCONV unsafe  "getprotobyname"-   c_getprotobyname :: CString -> IO (Ptr ProtocolEntry)---getProtocolByNumber :: ProtocolNumber -> IO ProtocolEntry-getProtocolByNumber num = withLock $ do- throwNoSuchThingIfNull "Network.BSD.getProtocolByNumber" ("no such protocol number: " ++ show num)-   $ c_getprotobynumber (fromIntegral num)- >>= peek--foreign import CALLCONV unsafe  "getprotobynumber"-   c_getprotobynumber :: CInt -> IO (Ptr ProtocolEntry)---getProtocolNumber :: ProtocolName -> IO ProtocolNumber-getProtocolNumber proto = do- (ProtocolEntry _ _ num) <- getProtocolByName proto- return num--#if !defined(mingw32_HOST_OS)-getProtocolEntry :: IO ProtocolEntry    -- Next Protocol Entry from DB-getProtocolEntry = withLock $ do- ent <- throwNoSuchThingIfNull "Network.BSD.getProtocolEntry" "no such protocol entry"-                $ c_getprotoent- peek ent--foreign import ccall unsafe  "getprotoent" c_getprotoent :: IO (Ptr ProtocolEntry)--setProtocolEntry :: Bool -> IO ()       -- Keep DB Open ?-setProtocolEntry flg = withLock $ c_setprotoent (fromBool flg)--foreign import ccall unsafe "setprotoent" c_setprotoent :: CInt -> IO ()--endProtocolEntry :: IO ()-endProtocolEntry = withLock $ c_endprotoent--foreign import ccall unsafe "endprotoent" c_endprotoent :: IO ()--getProtocolEntries :: Bool -> IO [ProtocolEntry]-getProtocolEntries stayOpen = withLock $ do-  setProtocolEntry stayOpen-  getEntries (getProtocolEntry) (endProtocolEntry)-#endif---- ------------------------------------------------------------------------------ Host lookups--data HostEntry =-  HostEntry  {-     hostName      :: HostName,         -- Official Name-     hostAliases   :: [HostName],       -- aliases-     hostFamily    :: Family,           -- Host Type (currently AF_INET)-     hostAddresses :: [HostAddress]     -- Set of Network Addresses  (in network byte order)-  } deriving (Read, Show, Typeable)--instance Storable HostEntry where-   sizeOf    _ = #const sizeof(struct hostent)-   alignment _ = alignment (undefined :: CInt) -- ???--   peek p = do-        h_name       <- (#peek struct hostent, h_name) p >>= peekCString-        h_aliases    <- (#peek struct hostent, h_aliases) p-                                >>= peekArray0 nullPtr-                                >>= mapM peekCString-        h_addrtype   <- (#peek struct hostent, h_addrtype) p-        -- h_length       <- (#peek struct hostent, h_length) p-        h_addr_list  <- (#peek struct hostent, h_addr_list) p-                                >>= peekArray0 nullPtr-                                >>= mapM peek-        return (HostEntry {-                        hostName       = h_name,-                        hostAliases    = h_aliases,-#if defined(HAVE_WINSOCK2_H)-                        hostFamily     = unpackFamily (fromIntegral (h_addrtype :: CShort)),-#else-                        hostFamily     = unpackFamily h_addrtype,-#endif-                        hostAddresses  = h_addr_list-                })--   poke = throwUnsupportedOperationPoke "HostEntry"----- convenience function:-hostAddress :: HostEntry -> HostAddress-hostAddress (HostEntry nm _ _ ls) =- case ls of-   []    -> error $ "Network.BSD.hostAddress: empty network address list for " ++ nm-   (x:_) -> x---- getHostByName must use the same lock as the *hostent functions--- may cause problems if called concurrently.---- | Resolve a 'HostName' to IPv4 address.-getHostByName :: HostName -> IO HostEntry-getHostByName name = withLock $ do-  withCString name $ \ name_cstr -> do-   ent <- throwNoSuchThingIfNull "Network.BSD.getHostByName" "no such host entry"-                $ c_gethostbyname name_cstr-   peek ent--foreign import CALLCONV safe "gethostbyname"-   c_gethostbyname :: CString -> IO (Ptr HostEntry)----- The locking of gethostbyaddr is similar to gethostbyname.--- | Get a 'HostEntry' corresponding to the given address and family.--- Note that only IPv4 is currently supported.-getHostByAddr :: Family -> HostAddress -> IO HostEntry-getHostByAddr family addr = do- with addr $ \ ptr_addr -> withLock $ do- throwNoSuchThingIfNull "Network.BSD.getHostByAddr" "no such host entry"-   $ c_gethostbyaddr ptr_addr (fromIntegral (sizeOf addr)) (packFamily family)- >>= peek--foreign import CALLCONV safe "gethostbyaddr"-   c_gethostbyaddr :: Ptr HostAddress -> CInt -> CInt -> IO (Ptr HostEntry)--#if defined(HAVE_GETHOSTENT) && !defined(mingw32_HOST_OS)-getHostEntry :: IO HostEntry-getHostEntry = withLock $ do- throwNoSuchThingIfNull "Network.BSD.getHostEntry" "unable to retrieve host entry"-   $ c_gethostent- >>= peek--foreign import ccall unsafe "gethostent" c_gethostent :: IO (Ptr HostEntry)--setHostEntry :: Bool -> IO ()-setHostEntry flg = withLock $ c_sethostent (fromBool flg)--foreign import ccall unsafe "sethostent" c_sethostent :: CInt -> IO ()--endHostEntry :: IO ()-endHostEntry = withLock $ c_endhostent--foreign import ccall unsafe "endhostent" c_endhostent :: IO ()--getHostEntries :: Bool -> IO [HostEntry]-getHostEntries stayOpen = do-  setHostEntry stayOpen-  getEntries (getHostEntry) (endHostEntry)-#endif---- ------------------------------------------------------------------------------ Accessing network information---- Same set of access functions as for accessing host,protocol and--- service system info, this time for the types of networks supported.---- network addresses are represented in host byte order.-type NetworkAddr = CULong--type NetworkName = String--data NetworkEntry =-  NetworkEntry {-     networkName        :: NetworkName,   -- official name-     networkAliases     :: [NetworkName], -- aliases-     networkFamily      :: Family,         -- type-     networkAddress     :: NetworkAddr-   } deriving (Read, Show, Typeable)--instance Storable NetworkEntry where-   sizeOf    _ = #const sizeof(struct hostent)-   alignment _ = alignment (undefined :: CInt) -- ???--   peek p = do-        n_name         <- (#peek struct netent, n_name) p >>= peekCString-        n_aliases      <- (#peek struct netent, n_aliases) p-                                >>= peekArray0 nullPtr-                                >>= mapM peekCString-        n_addrtype     <- (#peek struct netent, n_addrtype) p-        n_net          <- (#peek struct netent, n_net) p-        return (NetworkEntry {-                        networkName      = n_name,-                        networkAliases   = n_aliases,-                        networkFamily    = unpackFamily (fromIntegral-                                                        (n_addrtype :: CInt)),-                        networkAddress   = n_net-                })--   poke = throwUnsupportedOperationPoke "NetworkEntry"---#if !defined(mingw32_HOST_OS)-getNetworkByName :: NetworkName -> IO NetworkEntry-getNetworkByName name = withLock $ do- withCString name $ \ name_cstr -> do-  throwNoSuchThingIfNull "Network.BSD.getNetworkByName" "no such network entry"-    $ c_getnetbyname name_cstr-  >>= peek--foreign import ccall unsafe "getnetbyname"-   c_getnetbyname  :: CString -> IO (Ptr NetworkEntry)--getNetworkByAddr :: NetworkAddr -> Family -> IO NetworkEntry-getNetworkByAddr addr family = withLock $ do- throwNoSuchThingIfNull "Network.BSD.getNetworkByAddr" "no such network entry"-   $ c_getnetbyaddr addr (packFamily family)- >>= peek--foreign import ccall unsafe "getnetbyaddr"-   c_getnetbyaddr  :: NetworkAddr -> CInt -> IO (Ptr NetworkEntry)--getNetworkEntry :: IO NetworkEntry-getNetworkEntry = withLock $ do- throwNoSuchThingIfNull "Network.BSD.getNetworkEntry" "no more network entries"-          $ c_getnetent- >>= peek--foreign import ccall unsafe "getnetent" c_getnetent :: IO (Ptr NetworkEntry)---- | Open the network name database. The parameter specifies--- whether a connection is maintained open between various--- networkEntry calls-setNetworkEntry :: Bool -> IO ()-setNetworkEntry flg = withLock $ c_setnetent (fromBool flg)--foreign import ccall unsafe "setnetent" c_setnetent :: CInt -> IO ()---- | Close the connection to the network name database.-endNetworkEntry :: IO ()-endNetworkEntry = withLock $ c_endnetent--foreign import ccall unsafe "endnetent" c_endnetent :: IO ()---- | Get the list of network entries.-getNetworkEntries :: Bool -> IO [NetworkEntry]-getNetworkEntries stayOpen = do-  setNetworkEntry stayOpen-  getEntries (getNetworkEntry) (endNetworkEntry)-#endif---- Mutex for name service lockdown--{-# NOINLINE lock #-}-lock :: MVar ()-lock = unsafePerformIO $ withSocketsDo $ newMVar ()--withLock :: IO a -> IO a-withLock act = withMVar lock (\_ -> act)---- ------------------------------------------------------------------------------ Miscellaneous Functions---- | Calling getHostName returns the standard host name for the current--- processor, as set at boot time.--getHostName :: IO HostName-getHostName = do-  let size = 256-  allocaArray0 size $ \ cstr -> do-    throwSocketErrorIfMinus1_ "Network.BSD.getHostName" $ c_gethostname cstr (fromIntegral size)-    peekCString cstr--foreign import CALLCONV unsafe "gethostname"-   c_gethostname :: CString -> CSize -> IO CInt---- Helper function used by the exported functions that provides a--- Haskellised view of the enumerator functions:--getEntries :: IO a  -- read-           -> IO () -- at end-           -> IO [a]-getEntries getOne atEnd = loop-  where-    loop = do-      vv <- E.catch (liftM Just getOne)-            (\ e -> let _types = e :: IOException in return Nothing)-      case vv of-        Nothing -> return []-        Just v  -> loop >>= \ vs -> atEnd >> return (v:vs)---throwNoSuchThingIfNull :: String -> String -> IO (Ptr a) -> IO (Ptr a)-throwNoSuchThingIfNull loc desc act = do-  ptr <- act-  if (ptr == nullPtr)-   then ioError (ioeSetErrorString (mkIOError NoSuchThing loc Nothing Nothing) desc)-   else return ptr--throwUnsupportedOperationPoke :: String -> Ptr a -> a -> IO ()-throwUnsupportedOperationPoke typ _ _ =-  ioError $ ioeSetErrorString ioe "Operation not implemented"-  where-    ioe = mkIOError UnsupportedOperation-                    ("Network.BSD: instance Storable " ++ typ ++ ": poke")-                    Nothing-                    Nothing
+ Network/Socket.hs view
@@ -0,0 +1,217 @@+{-# LANGUAGE CPP #-}++#include "HsNetDef.h"++-----------------------------------------------------------------------------+-- |+-- Module      :  Network.Socket+-- Copyright   :  (c) The University of Glasgow 2001+-- License     :  BSD-style (see the file libraries/network/LICENSE)+--+-- Maintainer  :  libraries@haskell.org+-- Stability   :  provisional+-- Portability :  portable+--+-- This is the main module of the network package supposed to be+-- used with either "Network.Socket.ByteString" or+-- "Network.Socket.ByteString.Lazy" for sending/receiving.+--+-- Here are two minimal example programs using the TCP/IP protocol: a+-- server that echoes all data that it receives back (servicing only+-- one client) and a client using it.+--+-- > -- Echo server program+-- > module Main (main) where+-- >+-- > import Control.Concurrent (forkFinally)+-- > import qualified Control.Exception as E+-- > import Control.Monad (unless, forever, void)+-- > import qualified Data.ByteString as S+-- > import Network.Socket+-- > import Network.Socket.ByteString (recv, sendAll)+-- >+-- > main :: IO ()+-- > main = withSocketsDo $ do+-- >     addr <- resolve "3000"+-- >     E.bracket (open addr) close loop+-- >   where+-- >     resolve port = do+-- >         let hints = defaultHints {+-- >                 addrFlags = [AI_PASSIVE]+-- >               , addrSocketType = Stream+-- >               }+-- >         addr:_ <- getAddrInfo (Just hints) Nothing (Just port)+-- >         return addr+-- >     open addr = do+-- >         sock <- socket (addrFamily addr) (addrSocketType addr) (addrProtocol addr)+-- >         setSocketOption sock ReuseAddr 1+-- >         -- If the prefork technique is not used,+-- >         -- set CloseOnExec for the security reasons.+-- >         fd <- fdSocket sock+-- >         setCloseOnExecIfNeeded fd+-- >         bind sock (addrAddress addr)+-- >         listen sock 10+-- >         return sock+-- >     loop sock = forever $ do+-- >         (conn, peer) <- accept sock+-- >         putStrLn $ "Connection from " ++ show peer+-- >         void $ forkFinally (talk conn) (\_ -> close conn)+-- >     talk conn = do+-- >         msg <- recv conn 1024+-- >         unless (S.null msg) $ do+-- >           sendAll conn msg+-- >           talk conn+--+-- > {-# LANGUAGE OverloadedStrings #-}+-- > -- Echo client program+-- > module Main (main) where+-- >+-- > import qualified Control.Exception as E+-- > import qualified Data.ByteString.Char8 as C+-- > import Network.Socket+-- > import Network.Socket.ByteString (recv, sendAll)+-- >+-- > main :: IO ()+-- > main = withSocketsDo $ do+-- >     addr <- resolve "127.0.0.1" "3000"+-- >     E.bracket (open addr) close talk+-- >   where+-- >     resolve host port = do+-- >         let hints = defaultHints { addrSocketType = Stream }+-- >         addr:_ <- getAddrInfo (Just hints) (Just host) (Just port)+-- >         return addr+-- >     open addr = do+-- >         sock <- socket (addrFamily addr) (addrSocketType addr) (addrProtocol addr)+-- >         connect sock $ addrAddress addr+-- >         return sock+-- >     talk sock = do+-- >         sendAll sock "Hello, world!"+-- >         msg <- recv sock 1024+-- >         putStr "Received: "+-- >         C.putStrLn msg+--+-- The proper programming model is that one 'Socket' is handled by+-- a single thread. If multiple threads use one 'Socket' concurrently,+-- unexpected things would happen. There is one exception for multiple+-- threads vs a single 'Socket': one thread reads data from a 'Socket'+-- only and the other thread writes data to the 'Socket' only.+-----------------------------------------------------------------------------++-- In order to process this file, you need to have CALLCONV defined.++module Network.Socket+    (+    -- * Initialisation+      withSocketsDo++    -- * Address information+    , getAddrInfo+    -- ** Types+    , HostName+    , ServiceName+    , AddrInfo(..)+    , defaultHints+    -- ** Flags+    , AddrInfoFlag(..)+    , addrInfoFlagImplemented++    -- * Socket operations+    , connect+    , bind+    , listen+    , accept+    -- ** Closing+    , close+    , close'+    , shutdown+    , ShutdownCmd(..)++    -- * Socket options+    , SocketOption(..)+    , isSupportedSocketOption+    , getSocketOption+    , setSocketOption++    -- * Socket+    , Socket+    , socket+    , fdSocket+    , mkSocket+    , socketToHandle+    -- ** Types of Socket+    , SocketType(..)+    , isSupportedSocketType+    -- ** Family+    , Family(..)+    , isSupportedFamily+    , packFamily+    , unpackFamily+    -- ** Protocol number+    , ProtocolNumber+    , defaultProtocol+    -- * Basic socket address type+    , SockAddr(..)+    , isSupportedSockAddr+    , getPeerName+    , getSocketName+    -- ** Host address+    , HostAddress+    , hostAddressToTuple+    , tupleToHostAddress+    -- ** Host address6+    , HostAddress6+    , hostAddress6ToTuple+    , tupleToHostAddress6+    -- ** Flow Info+    , FlowInfo+    -- ** Scope ID+    , ScopeID+    , ifNameToIndex+    , ifIndexToName+    -- ** Port number+    , PortNumber+    , defaultPort+    , socketPortSafe+    , socketPort++    -- * UNIX-domain socket+    , isUnixDomainSocketAvailable+    , socketPair+    , sendFd+    , recvFd+    , getPeerCredential++    -- * Name information+    , getNameInfo+    , NameInfoFlag(..)++    -- * Low level+    -- ** socket operations+    , setCloseOnExecIfNeeded+    , getCloseOnExec+    , setNonBlockIfNeeded+    , getNonBlock+    -- ** Sending and receiving data+    , sendBuf+    , recvBuf+    , sendBufTo+    , recvBufFrom++    -- * Special constants+    , maxListenQueue+    ) where++import Network.Socket.Buffer hiding (sendBufTo, recvBufFrom)+import Network.Socket.Cbits+import Network.Socket.Fcntl+import Network.Socket.Handle+import Network.Socket.If+import Network.Socket.Info+import Network.Socket.Internal+import Network.Socket.Name hiding (getPeerName, getSocketName)+import Network.Socket.Options+import Network.Socket.Shutdown+import Network.Socket.SockAddr+import Network.Socket.Syscall hiding (connect, bind, accept)+import Network.Socket.Types+import Network.Socket.Unix
− Network/Socket.hsc
@@ -1,1966 +0,0 @@-{-# LANGUAGE CPP, ScopedTypeVariables, RecordWildCards #-}-{-# OPTIONS_GHC -fno-warn-orphans #-}-{-# OPTIONS_GHC -fno-warn-warnings-deprecations #-}--------------------------------------------------------------------------------- |--- Module      :  Network.Socket--- Copyright   :  (c) The University of Glasgow 2001--- License     :  BSD-style (see the file libraries/network/LICENSE)------ Maintainer  :  libraries@haskell.org--- Stability   :  provisional--- Portability :  portable------ This is the main module of the network package supposed to be--- used with either "Network.Socket.ByteString" or--- "Network.Socket.ByteString.Lazy" for sending/receiving.------ Here are two minimal example programs using the TCP/IP protocol: a--- server that echoes all data that it receives back (servicing only--- one client) and a client using it.------ > -- Echo server program--- > module Main (main) where--- >--- > import Control.Concurrent (forkFinally)--- > import qualified Control.Exception as E--- > import Control.Monad (unless, forever, void)--- > import qualified Data.ByteString as S--- > import Network.Socket hiding (recv)--- > import Network.Socket.ByteString (recv, sendAll)--- >--- > main :: IO ()--- > main = withSocketsDo $ do--- >     addr <- resolve "3000"--- >     E.bracket (open addr) close loop--- >   where--- >     resolve port = do--- >         let hints = defaultHints {--- >                 addrFlags = [AI_PASSIVE]--- >               , addrSocketType = Stream--- >               }--- >         addr:_ <- getAddrInfo (Just hints) Nothing (Just port)--- >         return addr--- >     open addr = do--- >         sock <- socket (addrFamily addr) (addrSocketType addr) (addrProtocol addr)--- >         setSocketOption sock ReuseAddr 1--- >         bind sock (addrAddress addr)--- >         -- If the prefork technique is not used,--- >         -- set CloseOnExec for the security reasons.--- >         let fd = fdSocket sock--- >         setCloseOnExecIfNeeded fd--- >         listen sock 10--- >         return sock--- >     loop sock = forever $ do--- >         (conn, peer) <- accept sock--- >         putStrLn $ "Connection from " ++ show peer--- >         void $ forkFinally (talk conn) (\_ -> close conn)--- >     talk conn = do--- >         msg <- recv conn 1024--- >         unless (S.null msg) $ do--- >           sendAll conn msg--- >           talk conn------ > {-# LANGUAGE OverloadedStrings #-}--- > -- Echo client program--- > module Main (main) where--- >--- > import qualified Control.Exception as E--- > import qualified Data.ByteString.Char8 as C--- > import Network.Socket hiding (recv)--- > import Network.Socket.ByteString (recv, sendAll)--- >--- > main :: IO ()--- > main = withSocketsDo $ do--- >     addr <- resolve "127.0.0.1" "3000"--- >     E.bracket (open addr) close talk--- >   where--- >     resolve host port = do--- >         let hints = defaultHints { addrSocketType = Stream }--- >         addr:_ <- getAddrInfo (Just hints) (Just host) (Just port)--- >         return addr--- >     open addr = do--- >         sock <- socket (addrFamily addr) (addrSocketType addr) (addrProtocol addr)--- >         connect sock $ addrAddress addr--- >         return sock--- >     talk sock = do--- >         sendAll sock "Hello, world!"--- >         msg <- recv sock 1024--- >         putStr "Received: "--- >         C.putStrLn msg------ The proper programming model is that one 'Socket' is handled by--- a single thread. If multiple threads use one 'Socket' concurrently,--- unexpected things would happen. There is one exception for multiple--- threads vs a single 'Socket': one thread reads data from a 'Socket'--- only and the other thread writes data to the 'Socket' only.--------------------------------------------------------------------------------#include "HsNet.h"-##include "HsNetDef.h"--module Network.Socket-    (-    -- * Initialisation-      withSocketsDo-    -- * Address information-    , getAddrInfo-    -- ** Types-    , HostName-    , ServiceName-    , AddrInfo(..)-    , defaultHints-    -- ** Flags-    , AddrInfoFlag(..)-    , addrInfoFlagImplemented-    -- * Socket operations-    , connect-    , bind-    , listen-    , accept-    -- ** Closing-    , close-    , close'-    , shutdown-    , ShutdownCmd(..)-    -- * Socket options-    , SocketOption(..)-    , isSupportedSocketOption-    , getSocketOption-    , setSocketOption-    -- * Socket-    , Socket(..)-    , socket-    , fdSocket-    , mkSocket-    , socketToHandle-    -- ** Types of Socket-    , SocketType(..)-    , isSupportedSocketType-    -- ** Family-    , Family(..)-    , isSupportedFamily-    -- ** Protocol number-    , ProtocolNumber-    , defaultProtocol-    -- * Socket address-    , SockAddr(..)-    , isSupportedSockAddr-    , getPeerName-    , getSocketName-    -- ** Host address-    , HostAddress-    , hostAddressToTuple-    , tupleToHostAddress-#if defined(IPV6_SOCKET_SUPPORT)-    -- ** Host address6-    , HostAddress6-    , hostAddress6ToTuple-    , tupleToHostAddress6-    -- ** Flow Info-    , FlowInfo-    -- ** Scope ID-    , ScopeID-# if defined(HAVE_IF_NAMETOINDEX)-    , ifNameToIndex-    , ifIndexToName-# endif-#endif-    -- ** Port number-    , PortNumber-    , defaultPort-    , socketPortSafe-    , socketPort-    -- * UNIX-domain socket-    , isUnixDomainSocketAvailable-    , socketPair-    , sendFd-    , recvFd-    , getPeerCredential-#if defined(IPV6_SOCKET_SUPPORT)-    -- * Name information-    , NameInfoFlag(..)-    , getNameInfo-#endif-    -- * Low level operations-    , setCloseOnExecIfNeeded-    , getCloseOnExec-    , setNonBlockIfNeeded-    , getNonBlock-    -- * Sending and receiving data-    , sendBuf-    , recvBuf-    , sendBufTo-    , recvBufFrom-    -- * Special constants-    , maxListenQueue-    -- * Deprecated-    -- ** Deprecated sending and receiving-    , send-    , sendTo-    , recv-    , recvFrom-    , recvLen-    -- ** Deprecated address functions-    , htonl-    , ntohl-    , inet_addr-    , inet_ntoa-    -- ** Deprecated socket operations-    , bindSocket-    , sClose-    -- ** Deprecated socket status-    , SocketStatus(..) -- fixme-    , isConnected-    , isBound-    , isListening-    , isReadable-    , isWritable-    , sIsConnected-    , sIsBound-    , sIsListening-    , sIsReadable-    , sIsWritable-    -- ** Deprecated special constants-    , aNY_PORT-    , iNADDR_ANY-#if defined(IPV6_SOCKET_SUPPORT)-    , iN6ADDR_ANY-#endif-    , sOMAXCONN-    , sOL_SOCKET-#ifdef SCM_RIGHTS-    , sCM_RIGHTS-#endif-    -- ** Decrecated internal functions-    , packFamily-    , unpackFamily-    , packSocketType-    -- ** Decrecated UNIX-domain functions-#if defined(HAVE_STRUCT_UCRED) || defined(HAVE_GETPEEREID)-    -- get the credentials of our domain socket peer.-    , getPeerCred-#if defined(HAVE_GETPEEREID)-    , getPeerEid-#endif-#endif-    ) where--import Data.Bits-import Data.Functor-import Data.List (foldl')-import Data.Maybe (isJust)-import Data.Word (Word8, Word32)-import Foreign.Ptr (Ptr, castPtr, nullPtr)-import Foreign.Storable (Storable(..))-import Foreign.C.Error-import Foreign.C.String (CString, withCString, withCStringLen, peekCString, peekCStringLen)-import Foreign.C.Types (CUInt(..), CChar)-import Foreign.C.Types (CInt(..), CSize(..))-import Foreign.Marshal.Alloc ( alloca, allocaBytes )-import Foreign.Marshal.Array ( peekArray )-import Foreign.Marshal.Utils ( maybeWith, with )--import System.IO-import Control.Monad (liftM, when, void)--import qualified Control.Exception as E-import Control.Concurrent.MVar-import Data.Typeable-import System.IO.Error--import GHC.Conc (threadWaitWrite)-# ifdef HAVE_ACCEPT4-import GHC.Conc (threadWaitRead)-# endif-##if MIN_VERSION_base(4,3,1)-import GHC.Conc (closeFdWith)-##endif-# if defined(mingw32_HOST_OS)-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 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\"@.-type HostName       = String-type ServiceName    = String---- ------------------------------------------------------------------------------- On Windows, our sockets are not put in non-blocking mode (non-blocking--- is not supported for regular file descriptors on Windows, and it would--- be a pain to support it only for sockets).  So there are two cases:------  - the threaded RTS uses safe calls for socket operations to get---    non-blocking I/O, just like the rest of the I/O library------  - with the non-threaded RTS, only some operations on sockets will be---    non-blocking.  Reads and writes go through the normal async I/O---    system.  accept() uses asyncDoProc so is non-blocking.  A handful---    of others (recvFrom, sendFd, recvFd) will block all threads - if this---    is a problem, -threaded is the workaround.----##if defined(mingw32_HOST_OS)-##define SAFE_ON_WIN safe-##else-##define SAFE_ON_WIN unsafe-##endif---------------------------------------------------------------------------------- Socket types--#if defined(mingw32_HOST_OS)-socket2FD  (MkSocket fd _ _ _ _) =-  -- HACK, 1 means True-  FD{fdFD = fd,fdIsSocket_ = 1}-#endif---- | Smart constructor for constructing a 'Socket'. It should only be--- called once for every new file descriptor. The caller must make--- sure that the socket is in non-blocking mode. See--- 'setNonBlockIfNeeded'.-mkSocket :: CInt-         -> Family-         -> SocketType-         -> ProtocolNumber-         -> SocketStatus-         -> IO Socket-mkSocket fd fam sType pNum stat = do-   mStat <- newMVar stat-   withSocketsDo $ return ()-   return $ MkSocket fd fam sType pNum mStat---- | This is the default protocol for a given service.-defaultProtocol :: ProtocolNumber-defaultProtocol = 0---------------------------------------------------------------------------------- SockAddr--instance Show SockAddr where-#if defined(DOMAIN_SOCKET_SUPPORT)-  showsPrec _ (SockAddrUnix str) = showString str-#endif-  showsPrec _ (SockAddrInet port ha)-   = showString (unsafePerformIO (inet_ntoa ha))-   . showString ":"-   . shows port-#if defined(IPV6_SOCKET_SUPPORT)-  showsPrec _ addr@(SockAddrInet6 port _ _ _)-   = showChar '['-   . showString (unsafePerformIO $-                 fst `liftM` getNameInfo [NI_NUMERICHOST] True False addr >>=-                 maybe (fail "showsPrec: impossible internal error") return)-   . showString "]:"-   . shows port-#endif-#if defined(CAN_SOCKET_SUPPORT)-  showsPrec _ (SockAddrCan ifidx) = shows ifidx-#endif-#if !(defined(IPV6_SOCKET_SUPPORT) \-      && defined(DOMAIN_SOCKET_SUPPORT) && defined(CAN_SOCKET_SUPPORT))-  showsPrec _ _ = error "showsPrec: not supported"-#endif---------------------------------------------------------------------------------- Connection Functions---- In the following connection and binding primitives.  The names of--- the equivalent C functions have been preserved where possible. It--- should be noted that some of these names used in the C library,--- \tr{bind} in particular, have a different meaning to many Haskell--- programmers and have thus been renamed by appending the prefix--- Socket.---- | Create a new socket using the given address family, socket type--- 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 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 <- socket (addrFamily addr) (addrSocketType addr) (addrProtocol addr)--- >>> 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)-       -> IO Socket      -- Unconnected Socket-socket family stype protocol = do-    c_stype <- packSocketTypeOrThrow "socket" stype-    fd <- throwSocketErrorIfMinus1Retry "Network.Socket.socket" $-                c_socket (packFamily family) c_stype protocol-    setNonBlockIfNeeded fd-    sock <- mkSocket fd family stype protocol NotConnected-#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 && (stype == Stream || stype == Datagram)) $-      E.catch (setSocketOption sock IPv6Only 0) $ (\(_ :: E.IOException) -> return ())-# elif !defined(__OpenBSD__)-    when (family == AF_INET6 && (stype == Stream || stype == Datagram)) $-      setSocketOption sock IPv6Only 0 `onException` close sock-# endif-#endif-    return sock---- | Build a pair of connected socket objects using the given address--- family, socket type, and protocol number.  Address family, socket--- type, and protocol number are as for the 'socket' function above.--- Availability: Unix.-socketPair :: Family              -- Family Name (usually AF_INET or AF_INET6)-           -> SocketType          -- Socket Type (usually Stream)-           -> ProtocolNumber      -- Protocol Number-           -> IO (Socket, Socket) -- unnamed and connected.-#if defined(DOMAIN_SOCKET_SUPPORT)-socketPair family stype protocol = do-    allocaBytes (2 * sizeOf (1 :: CInt)) $ \ fdArr -> do-    c_stype <- packSocketTypeOrThrow "socketPair" stype-    _rc <- throwSocketErrorIfMinus1Retry "Network.Socket.socketpair" $-                c_socketpair (packFamily family) c_stype protocol fdArr-    [fd1,fd2] <- peekArray 2 fdArr-    s1 <- mkNonBlockingSocket fd1-    s2 <- mkNonBlockingSocket fd2-    return (s1,s2)-  where-    mkNonBlockingSocket fd = do-       setNonBlockIfNeeded fd-       mkSocket fd family stype protocol Connected--foreign import ccall unsafe "socketpair"-  c_socketpair :: CInt -> CInt -> CInt -> Ptr CInt -> IO CInt-#else-socketPair _ _ _ = error "Network.Socket.socketPair"-#endif---------------------------------------------------------------------------------#if defined(mingw32_HOST_OS)-#else-fGetFd :: CInt-fGetFd = #const F_GETFD-fGetFl :: CInt-fGetFl = #const F_GETFL-fdCloexec :: CInt-fdCloexec = #const FD_CLOEXEC-oNonBlock :: CInt-oNonBlock = #const O_NONBLOCK-# if defined(HAVE_ACCEPT4)-sockNonBlock :: CInt-sockNonBlock = #const SOCK_NONBLOCK-sockCloexec :: CInt-sockCloexec = #const SOCK_CLOEXEC-# endif-#endif---- | Set the nonblocking flag on Unix.---   On Windows, nothing is done.-setNonBlockIfNeeded :: CInt -> IO ()-setNonBlockIfNeeded fd =-    System.Posix.Internals.setNonBlockingFD fd True---- | Set the close_on_exec flag on Unix.---   On Windows, nothing is done.------   Since 2.7.0.0.-setCloseOnExecIfNeeded :: CInt -> IO ()-#if defined(mingw32_HOST_OS)-setCloseOnExecIfNeeded _ = return ()-#else-setCloseOnExecIfNeeded fd = System.Posix.Internals.setCloseOnExec fd-#endif--#if !defined(mingw32_HOST_OS)-foreign import ccall unsafe "fcntl"-  c_fcntl_read  :: CInt -> CInt -> CInt -> IO CInt-#endif---- | Get the nonblocking flag.---   On Windows, this function always returns 'False'.------   Since 2.7.0.0.-getCloseOnExec :: CInt -> IO Bool-#if defined(mingw32_HOST_OS)-getCloseOnExec _ = return False-#else-getCloseOnExec fd = do-    flags <- c_fcntl_read fd fGetFd 0-    let ret = flags .&. fdCloexec-    return (ret /= 0)-#endif---- | Get the close_on_exec flag.---   On Windows, this function always returns 'False'.------   Since 2.7.0.0.-getNonBlock :: CInt -> IO Bool-#if defined(mingw32_HOST_OS)-getNonBlock _ = return False-#else-getNonBlock fd = do-    flags <- c_fcntl_read fd fGetFl 0-    let ret = flags .&. oNonBlock-    return (ret /= 0)-#endif---------------------------------------------------------------------------------- Binding a socket---- | Bind the socket to an address. The socket must not already be--- bound.  The 'Family' passed to @bind@ must be the--- same as that passed to 'socket'.  If the special port number--- 'defaultPort' is passed then the system assigns the next available--- use port.-bind :: Socket    -- Unconnected Socket-           -> SockAddr  -- Address to Bind to-           -> IO ()-bind (MkSocket s _family _stype _protocol socketStatus) addr = do- modifyMVar_ socketStatus $ \ status -> do- if status /= NotConnected-  then-   ioError $ userError $-     "Network.Socket.bind: can't bind to socket with status " ++ show status-  else do-   withSockAddr addr $ \p_addr sz -> do-   _status <- throwSocketErrorIfMinus1Retry "Network.Socket.bind" $-     c_bind s p_addr (fromIntegral sz)-   return Bound---------------------------------------------------------------------------------- Connecting a socket---- | Connect to a remote socket at address.-connect :: Socket    -- Unconnected Socket-        -> SockAddr  -- Socket address stuff-        -> IO ()-connect sock@(MkSocket s _family _stype _protocol socketStatus) addr = withSocketsDo $ do- modifyMVar_ socketStatus $ \currentStatus -> do- if currentStatus /= NotConnected && currentStatus /= Bound-  then-    ioError $ userError $-      errLoc ++ ": can't connect to socket with status " ++ show currentStatus-  else do-    withSockAddr addr $ \p_addr sz -> do--    let connectLoop = do-           r <- c_connect s p_addr (fromIntegral sz)-           if r == -1-               then do-#if !(defined(HAVE_WINSOCK2_H))-                   err <- getErrno-                   case () of-                     _ | err == eINTR       -> connectLoop-                     _ | err == eINPROGRESS -> connectBlocked---                   _ | err == eAGAIN      -> connectBlocked-                     _otherwise             -> throwSocketError errLoc-#else-                   throwSocketError errLoc-#endif-               else return ()--        connectBlocked = do-           threadWaitWrite (fromIntegral s)-           err <- getSocketOption sock SoError-           if (err == 0)-                then return ()-                else throwSocketErrorCode errLoc (fromIntegral err)--    connectLoop-    return Connected- where-   errLoc = "Network.Socket.connect: " ++ show sock---------------------------------------------------------------------------------- Listen---- | Listen for connections made to the socket.  The second argument--- specifies the maximum number of queued connections and should be at--- least 1; the maximum value is system-dependent (usually 5).-listen :: Socket  -- Connected & Bound Socket-       -> Int     -- Queue Length-       -> IO ()-listen (MkSocket s _family _stype _protocol socketStatus) backlog = do- modifyMVar_ socketStatus $ \ status -> do- if status /= Bound-   then-     ioError $ userError $-       "Network.Socket.listen: can't listen on socket with status " ++ show status-   else do-     throwSocketErrorIfMinus1Retry_ "Network.Socket.listen" $-       c_listen s (fromIntegral backlog)-     return Listening---------------------------------------------------------------------------------- Accept------ A call to `accept' only returns when data is available on the given--- socket, unless the socket has been set to non-blocking.  It will--- return a new socket which should be used to read the incoming data and--- should then be closed. Using the socket returned by `accept' allows--- incoming requests to be queued on the original socket.---- | Accept a connection.  The socket must be bound to an address and--- listening for connections.  The return value is a pair @(conn,--- address)@ where @conn@ is a new socket object usable to send and--- receive data on the connection, and @address@ is the address bound--- to the socket on the other end of the connection.-accept :: Socket                        -- Queue Socket-       -> IO (Socket,                   -- Readable Socket-              SockAddr)                 -- Peer details--accept sock@(MkSocket s family stype protocol status) = do- currentStatus <- readMVar status- if not $ isAcceptable family stype currentStatus-   then-     ioError $ userError $-       "Network.Socket.accept: can't accept socket (" ++-         show (family, stype, protocol) ++ ") with status " ++-         show currentStatus-   else do-     let sz = sizeOfSockAddrByFamily family-     allocaBytes sz $ \ sockaddr -> do-     zeroMemory sockaddr $ fromIntegral sz-#if defined(mingw32_HOST_OS)-     new_sock <--        if threaded-           then with (fromIntegral sz) $ \ ptr_len ->-                  throwSocketErrorIfMinus1Retry "Network.Socket.accept" $-                    c_accept_safe s sockaddr ptr_len-           else do-                paramData <- c_newAcceptParams s (fromIntegral sz) sockaddr-                rc        <- asyncDoProc c_acceptDoProc paramData-                new_sock  <- c_acceptNewSock    paramData-                c_free paramData-                when (rc /= 0) $-                     throwSocketErrorCode "Network.Socket.accept" (fromIntegral rc)-                return new_sock-#else-     with (fromIntegral sz) $ \ ptr_len -> do-# ifdef HAVE_ACCEPT4-     new_sock <- throwSocketErrorIfMinus1RetryMayBlock "Network.Socket.accept"-                        (threadWaitRead (fromIntegral s))-                        (c_accept4 s sockaddr ptr_len (sockNonBlock .|. sockCloexec))-# else-     new_sock <- throwSocketErrorWaitRead sock "Network.Socket.accept"-                        (c_accept s sockaddr ptr_len)-     setNonBlockIfNeeded new_sock-     setCloseOnExecIfNeeded new_sock-# endif /* HAVE_ACCEPT4 */-#endif-     addr <- peekSockAddr sockaddr-     sock' <- mkSocket new_sock family stype protocol Connected-     return (sock', addr)--#if defined(mingw32_HOST_OS)-foreign import ccall unsafe "HsNet.h acceptNewSock"-  c_acceptNewSock :: Ptr () -> IO CInt-foreign import ccall unsafe "HsNet.h newAcceptParams"-  c_newAcceptParams :: CInt -> CInt -> Ptr a -> IO (Ptr ())-foreign import ccall unsafe "HsNet.h &acceptDoProc"-  c_acceptDoProc :: FunPtr (Ptr () -> IO Int)-foreign import ccall unsafe "free"-  c_free:: Ptr a -> IO ()-#endif---------------------------------------------------------------------------------- ** Sending and receiving data---- $sendrecv------ 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.---------------------------------------------------------------------------------- sendTo & recvFrom---- | Send data to the socket.  The recipient can be specified--- 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.------ NOTE: blocking on Windows unless you compile with -threaded (see--- GHC ticket #1129)-{-# DEPRECATED sendTo "Use sendTo defined in \"Network.Socket.ByteString\"" #-}-sendTo :: Socket        -- (possibly) bound/connected Socket-       -> String        -- Data to send-       -> SockAddr-       -> IO Int        -- Number of Bytes sent-sendTo sock xs addr = do- withCStringLen xs $ \(str, len) -> do-   sendBufTo sock str len addr---- | Send data to the socket.  The recipient can be specified--- 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.-sendBufTo :: Socket            -- (possibly) bound/connected Socket-          -> Ptr a -> Int  -- Data to send-          -> SockAddr-          -> IO Int            -- Number of Bytes sent-sendBufTo sock@(MkSocket s _family _stype _protocol _status) ptr nbytes addr = do- withSockAddr addr $ \p_addr sz -> do-   liftM fromIntegral $-     throwSocketErrorWaitWrite sock "Network.Socket.sendBufTo" $-        c_sendto s ptr (fromIntegral $ nbytes) 0{-flags-}-                        p_addr (fromIntegral sz)---- | Receive data from the socket. The socket need not be in a--- connected state. Returns @(bytes, nbytes, address)@ where @bytes@--- is a @String@ of length @nbytes@ representing the data received and--- @address@ is a 'SockAddr' representing the address of the sending--- socket.------ NOTE: blocking on Windows unless you compile with -threaded (see--- GHC ticket #1129)-{-# DEPRECATED recvFrom "Use recvFrom defined in \"Network.Socket.ByteString\"" #-}-recvFrom :: Socket -> Int -> IO (String, Int, SockAddr)-recvFrom sock nbytes =-  allocaBytes nbytes $ \ptr -> do-    (len, sockaddr) <- recvBufFrom sock ptr nbytes-    str <- peekCStringLen (ptr, len)-    return (str, len, sockaddr)---- | Receive data from the socket, writing it into buffer instead of--- creating a new string.  The socket need not be in a connected--- state. Returns @(nbytes, address)@ where @nbytes@ is the number of--- bytes received and @address@ is a 'SockAddr' representing the--- address of the sending socket.------ NOTE: blocking on Windows unless you compile with -threaded (see--- GHC ticket #1129)-recvBufFrom :: Socket -> Ptr a -> Int -> IO (Int, SockAddr)-recvBufFrom sock@(MkSocket s family _stype _protocol _status) ptr nbytes- | nbytes <= 0 = ioError (mkInvalidRecvArgError "Network.Socket.recvBufFrom")- | otherwise   =-    withNewSockAddr family $ \ptr_addr sz -> do-      alloca $ \ptr_len -> do-        poke ptr_len (fromIntegral sz)-        len <- throwSocketErrorWaitRead sock "Network.Socket.recvBufFrom" $-                   c_recvfrom s ptr (fromIntegral nbytes) 0{-flags-}-                                ptr_addr ptr_len-        let len' = fromIntegral len-        if len' == 0-         then ioError (mkEOFError "Network.Socket.recvFrom")-         else do-           flg <- isConnected sock-             -- For at least one implementation (WinSock 2), recvfrom() ignores-             -- filling in the sockaddr for connected TCP sockets. Cope with-             -- this by using getPeerName instead.-           sockaddr <--                if flg then-                   getPeerName sock-                else-                   peekSockAddr ptr_addr-           return (len', sockaddr)---------------------------------------------------------------------------------- send & recv---- | 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.-{-# DEPRECATED 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 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-        -> IO Int     -- Number of Bytes sent-sendBuf sock@(MkSocket s _family _stype _protocol _status) str len = do-   liftM fromIntegral $-#if defined(mingw32_HOST_OS)--- 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)-      0-      (fromIntegral len)-#else-     throwSocketErrorWaitWrite sock "Network.Socket.sendBuf" $-        c_send s str (fromIntegral len) 0{-flags-}-#endif----- | Receive data from the socket.  The socket must be in a connected--- state. This function may return fewer bytes than specified.  If the--- message is longer than the specified length, it may be discarded--- depending on the type of socket.  This function may block until a--- message arrives.------ Considering hardware and network realities, the maximum number of--- bytes to receive should be a small power of 2, e.g., 4096.------ 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.-{-# DEPRECATED recv "Use recv defined in \"Network.Socket.ByteString\"" #-}-recv :: Socket -> Int -> IO String-recv sock l = fst <$> recvLen sock l--{-# DEPRECATED recvLen "Use recv defined in \"Network.Socket.ByteString\" with \"Data.Bytestring.length\"" #-}-recvLen :: Socket -> Int -> IO (String, Int)-recvLen sock nbytes =-     allocaBytes nbytes $ \ptr -> do-        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--- message is longer than the specified length, it may be discarded--- depending on the type of socket.  This function may block until a--- message arrives.------ Considering hardware and network realities, the maximum number of--- bytes to receive should be a small power of 2, e.g., 4096.------ 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@(MkSocket s _family _stype _protocol _status) ptr nbytes- | nbytes <= 0 = ioError (mkInvalidRecvArgError "Network.Socket.recvBuf")- | otherwise   = do-        len <--#if defined(mingw32_HOST_OS)--- see comment in sendBuf above.-            throwSocketErrorIfMinus1Retry "Network.Socket.recvBuf" $-                readRawBufferPtr "Network.Socket.recvBuf"-                (socket2FD sock) ptr 0 (fromIntegral nbytes)-#else-               throwSocketErrorWaitRead sock "Network.Socket.recvBuf" $-                   c_recv s (castPtr ptr) (fromIntegral nbytes) 0{-flags-}-#endif-        let len' = fromIntegral len-        if len' == 0-         then ioError (mkEOFError "Network.Socket.recvBuf")-         else return len'----- ------------------------------------------------------------------------------ socketPort------ The port number the given socket is currently connected to can be--- determined by calling $port$, is generally only useful when bind--- was given $aNY\_PORT$.---- | Getting the port of socket.---   `IOError` is thrown if a port is not available.-socketPort :: Socket            -- Connected & Bound Socket-           -> IO PortNumber     -- Port Number of Socket-socketPort sock@(MkSocket _ AF_INET _ _ _) = do-    (SockAddrInet port _) <- getSocketName sock-    return port-#if defined(IPV6_SOCKET_SUPPORT)-socketPort sock@(MkSocket _ AF_INET6 _ _ _) = do-    (SockAddrInet6 port _ _ _) <- getSocketName sock-    return port-#endif-socketPort (MkSocket _ family _ _ _) =-    ioError $ userError $-      "Network.Socket.socketPort: address family '" ++ show family ++-      "' not supported."----- ------------------------------------------------------------------------------ socketPortSafe--- | Getting the port of socket.-socketPortSafe :: Socket                -- Connected & Bound Socket-               -> IO (Maybe PortNumber) -- Port Number of Socket-socketPortSafe s = do-    sa <- getSocketName s-    return $ case sa of-      SockAddrInet port _      -> Just port-#if defined(IPV6_SOCKET_SUPPORT)-      SockAddrInet6 port _ _ _ -> Just port-#endif-      _                        -> Nothing---- ------------------------------------------------------------------------------ getPeerName---- Calling $getPeerName$ returns the address details of the machine,--- other than the local one, which is connected to the socket. This is--- used in programs such as FTP to determine where to send the--- returning data.  The corresponding call to get the details of the--- local machine is $getSocketName$.--getPeerName   :: Socket -> IO SockAddr-getPeerName (MkSocket s family _ _ _) = do- withNewSockAddr family $ \ptr sz -> do-   with (fromIntegral sz) $ \int_star -> do-   throwSocketErrorIfMinus1Retry_ "Network.Socket.getPeerName" $-     c_getpeername s ptr int_star-   _sz <- peek int_star-   peekSockAddr ptr--getSocketName :: Socket -> IO SockAddr-getSocketName (MkSocket s family _ _ _) = do- withNewSockAddr family $ \ptr sz -> do-   with (fromIntegral sz) $ \int_star -> do-   throwSocketErrorIfMinus1Retry_ "Network.Socket.getSocketName" $-     c_getsockname s ptr int_star-   peekSockAddr ptr---------------------------------------------------------------------------------- Socket Properties---- | Socket options for use with 'setSocketOption' and 'getSocketOption'.------ The existence of a constructor does not imply that the relevant option--- is supported on your system: see 'isSupportedSocketOption'-data SocketOption-    = Debug         -- ^ SO_DEBUG-    | ReuseAddr     -- ^ SO_REUSEADDR-    | Type          -- ^ SO_TYPE-    | SoError       -- ^ SO_ERROR-    | DontRoute     -- ^ SO_DONTROUTE-    | Broadcast     -- ^ SO_BROADCAST-    | SendBuffer    -- ^ SO_SNDBUF-    | RecvBuffer    -- ^ SO_RCVBUF-    | KeepAlive     -- ^ SO_KEEPALIVE-    | OOBInline     -- ^ SO_OOBINLINE-    | TimeToLive    -- ^ IP_TTL-    | MaxSegment    -- ^ TCP_MAXSEG-    | NoDelay       -- ^ TCP_NODELAY-    | Cork          -- ^ TCP_CORK-    | Linger        -- ^ SO_LINGER-    | ReusePort     -- ^ SO_REUSEPORT-    | RecvLowWater  -- ^ SO_RCVLOWAT-    | SendLowWater  -- ^ SO_SNDLOWAT-    | RecvTimeOut   -- ^ SO_RCVTIMEO-    | SendTimeOut   -- ^ SO_SNDTIMEO-    | UseLoopBack   -- ^ SO_USELOOPBACK-    | UserTimeout   -- ^ TCP_USER_TIMEOUT-    | IPv6Only      -- ^ IPV6_V6ONLY-    | CustomSockOpt (CInt, CInt)-    deriving (Show, Typeable)---- | Does the 'SocketOption' exist on this system?-isSupportedSocketOption :: SocketOption -> Bool-isSupportedSocketOption = isJust . packSocketOption---- | For a socket option, return Just (level, value) where level is the--- corresponding C option level constant (e.g. SOL_SOCKET) and value is--- the option constant itself (e.g. SO_DEBUG)--- If either constant does not exist, return Nothing.-packSocketOption :: SocketOption -> Maybe (CInt, CInt)-packSocketOption so =-  -- The Just here is a hack to disable GHC's overlapping pattern detection:-  -- the problem is if all constants are present, the fallback pattern is-  -- redundant, but if they aren't then it isn't. Hence we introduce an-  -- extra pattern (Nothing) that can't possibly happen, so that the-  -- fallback is always (in principle) necessary.-  -- I feel a little bad for including this, but such are the sacrifices we-  -- make while working with CPP - excluding the fallback pattern correctly-  -- would be a serious nuisance.-  -- (NB: comments elsewhere in this file refer to this one)-  case Just so of-#ifdef SOL_SOCKET-#ifdef SO_DEBUG-    Just Debug         -> Just ((#const SOL_SOCKET), (#const SO_DEBUG))-#endif-#ifdef SO_REUSEADDR-    Just ReuseAddr     -> Just ((#const SOL_SOCKET), (#const SO_REUSEADDR))-#endif-#ifdef SO_TYPE-    Just Type          -> Just ((#const SOL_SOCKET), (#const SO_TYPE))-#endif-#ifdef SO_ERROR-    Just SoError       -> Just ((#const SOL_SOCKET), (#const SO_ERROR))-#endif-#ifdef SO_DONTROUTE-    Just DontRoute     -> Just ((#const SOL_SOCKET), (#const SO_DONTROUTE))-#endif-#ifdef SO_BROADCAST-    Just Broadcast     -> Just ((#const SOL_SOCKET), (#const SO_BROADCAST))-#endif-#ifdef SO_SNDBUF-    Just SendBuffer    -> Just ((#const SOL_SOCKET), (#const SO_SNDBUF))-#endif-#ifdef SO_RCVBUF-    Just RecvBuffer    -> Just ((#const SOL_SOCKET), (#const SO_RCVBUF))-#endif-#ifdef SO_KEEPALIVE-    Just KeepAlive     -> Just ((#const SOL_SOCKET), (#const SO_KEEPALIVE))-#endif-#ifdef SO_OOBINLINE-    Just OOBInline     -> Just ((#const SOL_SOCKET), (#const SO_OOBINLINE))-#endif-#ifdef SO_LINGER-    Just Linger        -> Just ((#const SOL_SOCKET), (#const SO_LINGER))-#endif-#ifdef SO_REUSEPORT-    Just ReusePort     -> Just ((#const SOL_SOCKET), (#const SO_REUSEPORT))-#endif-#ifdef SO_RCVLOWAT-    Just RecvLowWater  -> Just ((#const SOL_SOCKET), (#const SO_RCVLOWAT))-#endif-#ifdef SO_SNDLOWAT-    Just SendLowWater  -> Just ((#const SOL_SOCKET), (#const SO_SNDLOWAT))-#endif-#ifdef SO_RCVTIMEO-    Just RecvTimeOut   -> Just ((#const SOL_SOCKET), (#const SO_RCVTIMEO))-#endif-#ifdef SO_SNDTIMEO-    Just SendTimeOut   -> Just ((#const SOL_SOCKET), (#const SO_SNDTIMEO))-#endif-#ifdef SO_USELOOPBACK-    Just UseLoopBack   -> Just ((#const SOL_SOCKET), (#const SO_USELOOPBACK))-#endif-#endif // SOL_SOCKET-#if HAVE_DECL_IPPROTO_IP-#ifdef IP_TTL-    Just TimeToLive    -> Just ((#const IPPROTO_IP), (#const IP_TTL))-#endif-#endif // HAVE_DECL_IPPROTO_IP-#if HAVE_DECL_IPPROTO_TCP-#ifdef TCP_MAXSEG-    Just MaxSegment    -> Just ((#const IPPROTO_TCP), (#const TCP_MAXSEG))-#endif-#ifdef TCP_NODELAY-    Just NoDelay       -> Just ((#const IPPROTO_TCP), (#const TCP_NODELAY))-#endif-#ifdef TCP_USER_TIMEOUT-    Just UserTimeout   -> Just ((#const IPPROTO_TCP), (#const TCP_USER_TIMEOUT))-#endif-#ifdef TCP_CORK-    Just Cork          -> Just ((#const IPPROTO_TCP), (#const TCP_CORK))-#endif-#endif // HAVE_DECL_IPPROTO_TCP-#if HAVE_DECL_IPPROTO_IPV6-#if HAVE_DECL_IPV6_V6ONLY-    Just IPv6Only      -> Just ((#const IPPROTO_IPV6), (#const IPV6_V6ONLY))-#endif-#endif // HAVE_DECL_IPPROTO_IPV6-    Just (CustomSockOpt opt) -> Just opt-    _             -> Nothing---- | Return the option level and option value if they exist,--- otherwise throw an error that begins "Network.Socket." ++ the String--- parameter-packSocketOption' :: String -> SocketOption -> IO (CInt, CInt)-packSocketOption' caller so = maybe err return (packSocketOption so)- where-  err = ioError . userError . concat $ ["Network.Socket.", caller,-    ": socket option ", show so, " unsupported on this system"]---- | Set a socket option that expects an Int value.--- There is currently no API to set e.g. the timeval socket options-setSocketOption :: Socket-                -> SocketOption -- Option Name-                -> Int          -- Option Value-                -> IO ()-setSocketOption (MkSocket s _ _ _ _) so v = do-   (level, opt) <- packSocketOption' "setSocketOption" so-   with (fromIntegral v) $ \ptr_v -> do-   throwSocketErrorIfMinus1_ "Network.Socket.setSocketOption" $-       c_setsockopt s level opt ptr_v-          (fromIntegral (sizeOf (undefined :: CInt)))-   return ()----- | Get a socket option that gives an Int value.--- There is currently no API to get e.g. the timeval socket options-getSocketOption :: Socket-                -> SocketOption  -- Option Name-                -> IO Int        -- Option Value-getSocketOption (MkSocket s _ _ _ _) so = do-   (level, opt) <- packSocketOption' "getSocketOption" so-   alloca $ \ptr_v ->-     with (fromIntegral (sizeOf (undefined :: CInt))) $ \ptr_sz -> do-       throwSocketErrorIfMinus1Retry_ "Network.Socket.getSocketOption" $-         c_getsockopt s level opt ptr_v ptr_sz-       fromIntegral `liftM` peek ptr_v----- | Getting process ID, user ID and group ID for UNIX-domain sockets.------   This is implemented with SO_PEERCRED on Linux and getpeereid()---   on BSD variants. Unfortunately, on some BSD variants---   getpeereid() returns unexpected results, rather than an error,---   for AF_INET sockets. It is the user's responsibility to make sure---   that the socket is a UNIX-domain socket.---   Also, on some BSD variants, getpeereid() does not return credentials---   for sockets created via 'socketPair', only separately created and then---   explicitly connected UNIX-domain sockets work on such systems.------   Since 2.7.0.0.-getPeerCredential :: Socket -> IO (Maybe CUInt, Maybe CUInt, Maybe CUInt)-#ifdef HAVE_STRUCT_UCRED-getPeerCredential sock = do-    (pid, uid, gid) <- getPeerCred sock-    if uid == maxBound then-        return (Nothing, Nothing, Nothing)-      else-        return (Just pid, Just uid, Just gid)-#elif defined(HAVE_GETPEEREID)-getPeerCredential sock = E.handle (\(E.SomeException _) -> return (Nothing,Nothing,Nothing)) $ do-    (uid, gid) <- getPeerEid sock-    return (Nothing, Just uid, Just gid)-#else-getPeerCredential _ = return (Nothing, Nothing, Nothing)-#endif--#if defined(HAVE_STRUCT_UCRED) || defined(HAVE_GETPEEREID)-{-# DEPRECATED getPeerCred "Use getPeerCredential instead" #-}--- | Returns the processID, userID and groupID of the socket's peer.------ Only available on platforms that support SO_PEERCRED or GETPEEREID(3)--- on domain sockets.--- GETPEEREID(3) returns userID and groupID. processID is always 0.-getPeerCred :: Socket -> IO (CUInt, CUInt, CUInt)-getPeerCred sock = do-#ifdef HAVE_STRUCT_UCRED-  let fd = fdSocket sock-  let sz = (#const sizeof(struct ucred))-  allocaBytes sz $ \ ptr_cr ->-   with (fromIntegral sz) $ \ ptr_sz -> do-     _ <- ($) throwSocketErrorIfMinus1Retry "Network.Socket.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-     gid <- (#peek struct ucred, gid) ptr_cr-     return (pid, uid, gid)-#else-  (uid,gid) <- getPeerEid sock-  return (0,uid,gid)-#endif--#ifdef HAVE_GETPEEREID-{-# DEPRECATED getPeerEid "Use getPeerCredential instead" #-}--- | 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-  let fd = fdSocket sock-  alloca $ \ ptr_uid ->-    alloca $ \ ptr_gid -> do-      throwSocketErrorIfMinus1Retry_ "Network.Socket.getPeerEid" $-        c_getpeereid fd ptr_uid ptr_gid-      uid <- peek ptr_uid-      gid <- peek ptr_gid-      return (uid, gid)-#endif-#endif---- | Whether or not UNIX-domain sockets are available.------   Since 3.0.0.0.-isUnixDomainSocketAvailable :: Bool-#if defined(DOMAIN_SOCKET_SUPPORT)-isUnixDomainSocketAvailable = True-#else-isUnixDomainSocketAvailable = False-#endif--##if !(MIN_VERSION_base(4,3,1))-closeFdWith closer fd = closer fd-##endif---- sending/receiving ancillary socket data; low-level mechanism--- for transmitting file descriptors, mainly.-sendFd :: Socket -> CInt -> IO ()-#if defined(DOMAIN_SOCKET_SUPPORT)-sendFd sock outfd = do-  _ <- throwSocketErrorWaitWrite sock "Network.Socket.sendFd" $ c_sendFd (fdSocket sock) outfd-  return ()-foreign import ccall SAFE_ON_WIN "sendFd" c_sendFd :: CInt -> CInt -> IO CInt-#else-sendFd _ _ = error "Network.Socket.sendFd"-#endif---- | Receive a file descriptor over a domain socket. Note that the resulting--- file descriptor may have to be put into non-blocking mode in order to be--- used safely. See 'setNonBlockIfNeeded'.-recvFd :: Socket -> IO CInt-#if defined(DOMAIN_SOCKET_SUPPORT)-recvFd sock = do-  theFd <- throwSocketErrorWaitRead sock "Network.Socket.recvFd" $-               c_recvFd (fdSocket sock)-  return theFd-foreign import ccall SAFE_ON_WIN "recvFd" c_recvFd :: CInt -> IO CInt-#else-recvFd _ = error "Network.Socket.recvFd"-#endif---- ------------------------------------------------------------------------------ Utility Functions--{-# DEPRECATED aNY_PORT "Use defaultPort instead" #-}-aNY_PORT :: PortNumber-aNY_PORT = 0--defaultPort :: PortNumber-defaultPort = 0---- | The IPv4 wild card address.--{-# DEPRECATED iNADDR_ANY "Use getAddrInfo instead" #-}-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--{-# DEPRECATED htonl "Use getAddrInfo instead" #-}-{-# DEPRECATED ntohl "Use getAddrInfo instead" #-}--#if defined(IPV6_SOCKET_SUPPORT)--- | The IPv6 wild card address.--{-# DEPRECATED iN6ADDR_ANY "Use getAddrInfo instead" #-}-iN6ADDR_ANY :: HostAddress6-iN6ADDR_ANY = (0, 0, 0, 0)-#endif--{-# DEPRECATED sOMAXCONN "Use maxListenQueue instead" #-}-sOMAXCONN :: Int-sOMAXCONN = #const SOMAXCONN--{-# DEPRECATED sOL_SOCKET "This is not necessary anymore" #-}-sOL_SOCKET :: Int-sOL_SOCKET = #const SOL_SOCKET--#ifdef SCM_RIGHTS-{-# DEPRECATED sCM_RIGHTS "This is not necessary anymore" #-}-sCM_RIGHTS :: Int-sCM_RIGHTS = #const SCM_RIGHTS-#endif---- | This is the value of SOMAXCONN, typically 128.--- 128 is good enough for normal network servers but--- is too small for high performance servers.-maxListenQueue :: Int-maxListenQueue = sOMAXCONN---- -------------------------------------------------------------------------------data ShutdownCmd- = ShutdownReceive- | ShutdownSend- | ShutdownBoth- deriving Typeable--sdownCmdToInt :: ShutdownCmd -> CInt-sdownCmdToInt ShutdownReceive = 0-sdownCmdToInt ShutdownSend    = 1-sdownCmdToInt ShutdownBoth    = 2---- | Shut down one or both halves of the connection, depending on the--- second argument to the function.  If the second argument is--- 'ShutdownReceive', further receives are disallowed.  If it is--- 'ShutdownSend', further sends are disallowed.  If it is--- 'ShutdownBoth', further sends and receives are disallowed.-shutdown :: Socket -> ShutdownCmd -> IO ()-shutdown (MkSocket s _ _ _ _) stype = do-  throwSocketErrorIfMinus1Retry_ "Network.Socket.shutdown" $-    c_shutdown s (sdownCmdToInt stype)-  return ()---- --------------------------------------------------------------------------------- | Close the socket. This function does not throw exceptions even if---   the underlying system call returns errors.------   Sending data to or receiving data from closed socket---   may lead to undefined behaviour.------   If multiple threads use the same socket and one uses 'fdSocket' and---   the other use 'close', unexpected behavior may happen.---   For more information, please refer to the documentation of 'fdSocket'.-close :: Socket -> IO ()-close (MkSocket s _ _ _ socketStatus) = modifyMVar_ socketStatus $ \ status ->-   case status of-     ConvertedToHandle -> return ConvertedToHandle-     Closed            -> return Closed-     _                 -> do-         -- closeFdWith avoids the deadlock of IO manager.-         closeFdWith (void . c_close . fromIntegral) (fromIntegral s)-         return Closed---- | Close the socket. This function throws exceptions if---   the underlying system call returns errors.------   Sending data to or receiving data from closed socket---   may lead to undefined behaviour.-close' :: Socket -> IO ()-close' (MkSocket s _ _ _ socketStatus) = modifyMVar_ socketStatus $ \ status ->-   case status of-     ConvertedToHandle -> ioError (userError ("close: converted to a Handle, use hClose instead"))-     Closed            -> return Closed-     _                 -> do-         -- closeFdWith avoids the deadlock of IO manager.-         -- closeFd throws exceptions.-         closeFdWith (closeFd . fromIntegral) (fromIntegral s)-         return Closed---- --------------------------------------------------------------------------------- | Determines whether 'close' has been used on the 'Socket'. This--- does /not/ indicate any status about the socket beyond this. If the--- socket has been closed remotely, this function can still return--- 'True'.-isConnected :: Socket -> IO Bool-isConnected (MkSocket _ _ _ _ status) = do-    value <- readMVar status-    return (value == Connected)-{-# DEPRECATED isConnected "SocketStatus will be removed" #-}---- -------------------------------------------------------------------------------- Socket Predicates--isBound :: Socket -> IO Bool-isBound (MkSocket _ _ _ _ status) = do-    value <- readMVar status-    return (value == Bound)-{-# DEPRECATED isBound "SocketStatus will be removed" #-}--isListening :: Socket -> IO Bool-isListening (MkSocket _ _ _  _ status) = do-    value <- readMVar status-    return (value == Listening)-{-# DEPRECATED isListening "SocketStatus will be removed" #-}--isReadable  :: Socket -> IO Bool-isReadable (MkSocket _ _ _ _ status) = do-    value <- readMVar status-    return (value == Listening || value == Connected)-{-# DEPRECATED isReadable "SocketStatus will be removed" #-}--isWritable  :: Socket -> IO Bool-isWritable = isReadable -- sort of.-{-# DEPRECATED isWritable "SocketStatus will be removed" #-}--isAcceptable :: Family -> SocketType -> SocketStatus -> Bool-#if defined(DOMAIN_SOCKET_SUPPORT)-isAcceptable AF_UNIX sockTyp status-    | sockTyp == Stream || sockTyp == SeqPacket =-        status == Connected || status == Bound || status == Listening-isAcceptable AF_UNIX _ _ = False-#endif-isAcceptable _ _ status = status == Connected || status == Listening-{-# DEPRECATED isAcceptable "SocketStatus will be removed" #-}---- -------------------------------------------------------------------------------- Internet address manipulation routines:--{-# DEPRECATED inet_addr "Use \"getAddrInfo\" instead" #-}-inet_addr :: String -> IO HostAddress-inet_addr ipstr = withSocketsDo $ do-   withCString ipstr $ \str -> do-   had <- c_inet_addr str-   if had == maxBound-    then ioError $ userError $-      "Network.Socket.inet_addr: Malformed address: " ++ ipstr-    else return had  -- network byte order--{-# DEPRECATED inet_ntoa "Use \"getNameInfo\" instead" #-}-inet_ntoa :: HostAddress -> IO String-inet_ntoa haddr = withSocketsDo $ do-  pstr <- c_inet_ntoa haddr-  peekCString pstr---- | Turns a Socket into an 'Handle'. By default, the new handle is--- unbuffered. Use 'System.IO.hSetBuffering' to change the buffering.------ Note that since a 'Handle' is automatically closed by a finalizer--- when it is no longer referenced, you should avoid doing any more--- operations on the 'Socket' after calling 'socketToHandle'.  To--- close the 'Socket' after 'socketToHandle', call 'System.IO.hClose'--- on the 'Handle'.--socketToHandle :: Socket -> IOMode -> IO Handle-socketToHandle s@(MkSocket fd _ _ _ socketStatus) mode = do- modifyMVar socketStatus $ \ status ->-    if status == ConvertedToHandle-        then ioError (userError ("socketToHandle: already a Handle"))-        else do-    h <- fdToHandle' (fromIntegral fd) (Just GHC.IO.Device.Stream) True (show s) mode True{-bin-}-    hSetBuffering h NoBuffering-    return (ConvertedToHandle, h)---- | Pack a list of values into a bitmask.  The possible mappings from--- value to bit-to-set are given as the first argument.  We assume--- that each value can cause exactly one bit to be set; unpackBits will--- break if this property is not true.--packBits :: (Eq a, Num b, Bits b) => [(a, b)] -> [a] -> b--packBits mapping xs = foldl' pack 0 mapping-    where pack acc (k, v) | k `elem` xs = acc .|. v-                          | otherwise   = acc---- | Unpack a bitmask into a list of values.--unpackBits :: (Num b, Bits b) => [(a, b)] -> b -> [a]---- Be permissive and ignore unknown bit values. At least on OS X,--- getaddrinfo returns an ai_flags field with bits set that have no--- entry in <netdb.h>.-unpackBits [] _    = []-unpackBits ((k,v):xs) r-    | r .&. v /= 0 = k : unpackBits xs (r .&. complement v)-    | otherwise    = unpackBits xs r---------------------------------------------------------------------------------- Address and service lookups--#if defined(IPV6_SOCKET_SUPPORT)---- | Flags that control the querying behaviour of 'getAddrInfo'.---   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".-    --   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)--aiFlagMapping :: [(AddrInfoFlag, CInt)]--aiFlagMapping =-    [-#if HAVE_DECL_AI_ADDRCONFIG-     (AI_ADDRCONFIG, #const AI_ADDRCONFIG),-#else-     (AI_ADDRCONFIG, 0),-#endif-#if HAVE_DECL_AI_ALL-     (AI_ALL, #const AI_ALL),-#else-     (AI_ALL, 0),-#endif-     (AI_CANONNAME, #const AI_CANONNAME),-     (AI_NUMERICHOST, #const AI_NUMERICHOST),-#if HAVE_DECL_AI_NUMERICSERV-     (AI_NUMERICSERV, #const AI_NUMERICSERV),-#else-     (AI_NUMERICSERV, 0),-#endif-     (AI_PASSIVE, #const AI_PASSIVE),-#if HAVE_DECL_AI_V4MAPPED-     (AI_V4MAPPED, #const AI_V4MAPPED)-#else-     (AI_V4MAPPED, 0)-#endif-    ]---- | Indicate whether the given 'AddrInfoFlag' will have any effect on--- this system.-addrInfoFlagImplemented :: AddrInfoFlag -> Bool-addrInfoFlagImplemented f = packBits aiFlagMapping [f] /= 0--data AddrInfo =-    AddrInfo {-        addrFlags :: [AddrInfoFlag],-        addrFamily :: Family,-        addrSocketType :: SocketType,-        addrProtocol :: ProtocolNumber,-        addrAddress :: SockAddr,-        addrCanonName :: Maybe String-        }-    deriving (Eq, Show, Typeable)--instance Storable AddrInfo where-    sizeOf    _ = #const sizeof(struct addrinfo)-    alignment _ = alignment (undefined :: CInt)--    peek p = do-        ai_flags <- (#peek struct addrinfo, ai_flags) p-        ai_family <- (#peek struct addrinfo, ai_family) p-        ai_socktype <- (#peek struct addrinfo, ai_socktype) p-        ai_protocol <- (#peek struct addrinfo, ai_protocol) p-        ai_addr <- (#peek struct addrinfo, ai_addr) p >>= peekSockAddr-        ai_canonname_ptr <- (#peek struct addrinfo, ai_canonname) p--        ai_canonname <- if ai_canonname_ptr == nullPtr-                        then return Nothing-                        else liftM Just $ peekCString ai_canonname_ptr--        socktype <- unpackSocketType' "AddrInfo.peek" ai_socktype-        return (AddrInfo-                {-                 addrFlags = unpackBits aiFlagMapping ai_flags,-                 addrFamily = unpackFamily ai_family,-                 addrSocketType = socktype,-                 addrProtocol = ai_protocol,-                 addrAddress = ai_addr,-                 addrCanonName = ai_canonname-                })--    poke p (AddrInfo flags family socketType protocol _ _) = do-        c_stype <- packSocketTypeOrThrow "AddrInfo.poke" socketType--        (#poke struct addrinfo, ai_flags) p (packBits aiFlagMapping flags)-        (#poke struct addrinfo, ai_family) p (packFamily family)-        (#poke struct addrinfo, ai_socktype) p c_stype-        (#poke struct addrinfo, ai_protocol) p protocol--        -- stuff below is probably not needed, but let's zero it for safety--        (#poke struct addrinfo, ai_addrlen) p (0::CSize)-        (#poke struct addrinfo, ai_addr) p nullPtr-        (#poke struct addrinfo, ai_canonname) p nullPtr-        (#poke struct addrinfo, ai_next) p nullPtr---- | 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)--niFlagMapping :: [(NameInfoFlag, CInt)]--niFlagMapping = [(NI_DGRAM, #const NI_DGRAM),-                 (NI_NAMEREQD, #const NI_NAMEREQD),-                 (NI_NOFQDN, #const NI_NOFQDN),-                 (NI_NUMERICHOST, #const NI_NUMERICHOST),-                 (NI_NUMERICSERV, #const NI_NUMERICSERV)]---- | 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,-                         addrSocketType = NoSocketType,-                         addrProtocol = defaultProtocol,-                         addrAddress = undefined,-                         addrCanonName = undefined-                        }---- | Shows the fields of 'defaultHints', without inspecting the by-default undefined fields 'addrAddress' and 'addrCanonName'.-showDefaultHints :: AddrInfo -> String-showDefaultHints AddrInfo{..} = concat-    [ "AddrInfo {"-    , "addrFlags = "-    , show addrFlags-    , ", addrFamily = "-    , show addrFamily-    , ", addrSocketType = "-    , show addrSocketType-    , ", addrProtocol = "-    , show addrProtocol-    , ", addrAddress = "-    , "<assumed to be undefined>"-    , ", addrCanonName = "-    , "<assumed to be undefined>"-    , "}"-    ]---- | Resolve a host or service name to one or more addresses.--- The 'AddrInfo' values that this function returns contain 'SockAddr'--- values that you can pass directly to 'connect' or--- 'bind'.------ This function is protocol independent.  It can return both IPv4 and--- IPv6 address information.------ The 'AddrInfo' argument specifies the preferred query behaviour,--- socket options, or protocol.  You can override these conveniently--- using Haskell's record update syntax on 'defaultHints', for example--- as follows:------ >>> 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--- network address (dotted quad for IPv4, colon-separated hex for--- IPv6) or a hostname.  In the latter case, its addresses will be--- looked up unless 'AI_NUMERICHOST' is specified as a hint.  If you--- do not provide a 'HostName' value /and/ do not set 'AI_PASSIVE' as--- a hint, network addresses in the result will contain the address of--- the loopback interface.------ If the query fails, this function throws an IO exception instead of--- returning an empty list.  Otherwise, it returns a non-empty list--- of 'AddrInfo' values.------ There are several reasons why a query might result in several--- values.  For example, the queried-for host could be multihomed, or--- the service might be available via several protocols.------ Note: the order of arguments is slightly different to that defined--- for @getaddrinfo@ in RFC 2553.  The 'AddrInfo' parameter comes first--- to make partial application easier.------ >>> 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-            -> Maybe ServiceName -- ^ service name to look up-            -> IO [AddrInfo] -- ^ resolved addresses, with "best" first--getAddrInfo hints node service = withSocketsDo $-  maybeWith withCString node $ \c_node ->-    maybeWith withCString service $ \c_service ->-      maybeWith with filteredHints $ \c_hints ->-        alloca $ \ptr_ptr_addrs -> do-          ret <- c_getaddrinfo c_node c_service c_hints ptr_ptr_addrs-          case ret of-            0 -> do ptr_addrs <- peek ptr_ptr_addrs-                    ais <- followAddrInfo ptr_addrs-                    c_freeaddrinfo ptr_addrs-                    return ais-            _ -> do err <- gai_strerror ret-                    let message = concat-                            [ "Network.Socket.getAddrInfo (called with preferred socket type/protocol: "-                            , maybe (show hints) showDefaultHints hints-                            , ", host name: "-                            , show node-                            , ", service name: "-                            , show service-                            , ")"-                            ]-                    ioError (ioeSetErrorString-                             (mkIOError NoSuchThing message Nothing-                              Nothing) err)-    -- Leaving out the service and using AI_NUMERICSERV causes a-    -- segfault on OS X 10.8.2. This code removes AI_NUMERICSERV-    -- (which has no effect) in that case.-  where-#if defined(darwin_HOST_OS)-    filteredHints = case service of-        Nothing -> fmap (\ h -> h { addrFlags = delete AI_NUMERICSERV (addrFlags h) }) hints-        _       -> hints-#else-    filteredHints = hints-#endif--followAddrInfo :: Ptr AddrInfo -> IO [AddrInfo]--followAddrInfo ptr_ai | ptr_ai == nullPtr = return []-                      | otherwise = do-    a <- peek ptr_ai-    as <- (#peek struct addrinfo, ai_next) ptr_ai >>= followAddrInfo-    return (a:as)--foreign import ccall safe "hsnet_getaddrinfo"-    c_getaddrinfo :: CString -> CString -> Ptr AddrInfo -> Ptr (Ptr AddrInfo)-                  -> IO CInt--foreign import ccall safe "hsnet_freeaddrinfo"-    c_freeaddrinfo :: Ptr AddrInfo -> IO ()--gai_strerror :: CInt -> IO String--#ifdef HAVE_GAI_STRERROR-gai_strerror n = c_gai_strerror n >>= peekCString--foreign import ccall safe "gai_strerror"-    c_gai_strerror :: CInt -> IO CString-#else-gai_strerror n = ioError $ userError $ "Network.Socket.gai_strerror not supported: " ++ show n-#endif--withCStringIf :: Bool -> Int -> (CSize -> CString -> IO a) -> IO a-withCStringIf False _ f = f 0 nullPtr-withCStringIf True n f = allocaBytes n (f (fromIntegral n))---- | Resolve an address to a host or service name.--- This function is protocol independent.--- 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.------ If the query fails, this function throws an IO exception.------ Example:--- @---   (hostName, _) <- getNameInfo [] True False myAddress--- @--getNameInfo :: [NameInfoFlag] -- ^ flags to control lookup behaviour-            -> Bool -- ^ whether to look up a hostname-            -> Bool -- ^ whether to look up a service name-            -> SockAddr -- ^ the address to look up-            -> IO (Maybe HostName, Maybe ServiceName)--getNameInfo flags doHost doService addr = withSocketsDo $-  withCStringIf doHost (#const NI_MAXHOST) $ \c_hostlen c_host ->-    withCStringIf doService (#const NI_MAXSERV) $ \c_servlen c_serv -> do-      withSockAddr addr $ \ptr_addr sz -> do-        ret <- c_getnameinfo ptr_addr (fromIntegral sz) c_host c_hostlen-                             c_serv c_servlen (packBits niFlagMapping flags)-        case ret of-          0 -> do-            let peekIf doIf c_val = if doIf-                                     then liftM Just $ peekCString c_val-                                     else return Nothing-            host <- peekIf doHost c_host-            serv <- peekIf doService c_serv-            return (host, serv)-          _ -> do err <- gai_strerror ret-                  let message = concat-                        [ "Network.Socket.getNameInfo (called with flags: "-                        , show flags-                        , ", hostname lookup: "-                        , show doHost-                        , ", service name lookup: "-                        , show doService-                        , ", socket address: "-                        , show addr-                        , ")"-                        ]-                  ioError (ioeSetErrorString-                           (mkIOError NoSuchThing message Nothing-                            Nothing) err)--foreign import ccall safe "hsnet_getnameinfo"-    c_getnameinfo :: Ptr SockAddr -> CInt{-CSockLen???-} -> CString -> CSize -> CString-                  -> CSize -> CInt -> IO CInt-#endif--mkInvalidRecvArgError :: String -> IOError-mkInvalidRecvArgError loc = ioeSetErrorString (mkIOError-                                    InvalidArgument-                                    loc Nothing Nothing) "non-positive length"--mkEOFError :: String -> IOError-mkEOFError loc = ioeSetErrorString (mkIOError EOF loc Nothing Nothing) "end of file"---- ------------------------------------------------------------------------------ foreign imports from the C library--foreign import ccall unsafe "hsnet_inet_ntoa"-  c_inet_ntoa :: HostAddress -> IO (Ptr CChar)--foreign import CALLCONV unsafe "inet_addr"-  c_inet_addr :: Ptr CChar -> IO HostAddress--foreign import CALLCONV unsafe "shutdown"-  c_shutdown :: CInt -> CInt -> IO CInt--closeFd :: CInt -> IO ()-closeFd fd = throwSocketErrorIfMinus1_ "Network.Socket.close" $ c_close fd--#if !defined(WITH_WINSOCK)-foreign import ccall unsafe "close"-  c_close :: CInt -> IO CInt-#else-foreign import stdcall unsafe "closesocket"-  c_close :: CInt -> IO CInt-#endif--foreign import CALLCONV unsafe "socket"-  c_socket :: CInt -> CInt -> CInt -> IO CInt-foreign import CALLCONV unsafe "bind"-  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-#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--#if defined(mingw32_HOST_OS)-foreign import CALLCONV safe "accept"-  c_accept_safe :: CInt -> Ptr SockAddr -> Ptr CInt{-CSockLen???-} -> IO CInt--foreign import ccall unsafe "rtsSupportsBoundThreads" threaded :: Bool-#endif--foreign import CALLCONV unsafe "send"-  c_send :: CInt -> Ptr a -> CSize -> CInt -> IO CInt-foreign import CALLCONV SAFE_ON_WIN "sendto"-  c_sendto :: CInt -> Ptr a -> CSize -> CInt -> Ptr SockAddr -> CInt -> IO CInt-foreign import CALLCONV unsafe "recv"-  c_recv :: CInt -> Ptr CChar -> CSize -> CInt -> IO CInt-foreign import CALLCONV SAFE_ON_WIN "recvfrom"-  c_recvfrom :: CInt -> Ptr a -> CSize -> CInt -> Ptr SockAddr -> Ptr CInt -> IO CInt-foreign import CALLCONV unsafe "getpeername"-  c_getpeername :: CInt -> Ptr SockAddr -> Ptr CInt -> IO CInt-foreign import CALLCONV unsafe "getsockname"-  c_getsockname :: CInt -> Ptr SockAddr -> Ptr CInt -> IO CInt--foreign import CALLCONV unsafe "getsockopt"-  c_getsockopt :: CInt -> CInt -> CInt -> Ptr CInt -> Ptr CInt -> IO CInt-foreign import CALLCONV unsafe "setsockopt"-  c_setsockopt :: CInt -> CInt -> CInt -> Ptr CInt -> CInt -> IO CInt--#if defined(HAVE_GETPEEREID)-foreign import CALLCONV unsafe "getpeereid"-  c_getpeereid :: CInt -> Ptr CUInt -> Ptr CUInt -> IO CInt-#endif--- ------------------------------------------------------------------------------ * Deprecated aliases---- $deprecated-aliases------ 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 "SocketStatus will be removed" #-}--sIsConnected :: Socket -> IO Bool-sIsConnected = isConnected--{-# DEPRECATED sIsBound "SocketStatus will be removed" #-}--sIsBound :: Socket -> IO Bool-sIsBound = isBound--{-# DEPRECATED sIsListening "SocketStatus will be removed" #-}--sIsListening :: Socket -> IO Bool-sIsListening = isListening--{-# DEPRECATED sIsReadable "SocketStatus will be removed" #-}--sIsReadable  :: Socket -> IO Bool-sIsReadable = isReadable--{-# DEPRECATED sIsWritable "SocketStatus will be removed" #-}--sIsWritable  :: Socket -> IO Bool-sIsWritable = isWritable--#if defined(HAVE_IF_NAMETOINDEX)--- | Returns the index corresponding to the interface name.------   Since 2.7.0.0.-ifNameToIndex :: String -> IO (Maybe Int)-ifNameToIndex ifname = do-  index <- withCString ifname c_if_nametoindex-  -- On failure zero is returned. We'll return Nothing.-  return $ if index == 0 then Nothing else Just $ fromIntegral index---- | Returns the interface name corresponding to the index.------   Since 2.7.0.0.-ifIndexToName :: Int -> IO (Maybe String)-ifIndexToName ifn = allocaBytes 16 $ \ptr -> do -- 16 == IFNAMSIZ-    r <- c_if_indextoname (fromIntegral ifn) ptr-    if r == nullPtr then-        return Nothing-      else-        Just <$> peekCString ptr--foreign import CALLCONV safe "if_nametoindex"-   c_if_nametoindex :: CString -> IO CUInt--foreign import CALLCONV safe "if_indextoname"-   c_if_indextoname :: CUInt -> CString -> IO CString-#endif
+ Network/Socket/Address.hs view
@@ -0,0 +1,25 @@+-- | This module provides extensible APIs for socket addresses.+--+module Network.Socket.Address (+    -- * Socket Address+      SocketAddress(..)+    , getPeerName+    , getSocketName+    -- * Socket operations+    , connect+    , bind+    , accept+    -- * Sending and receiving ByteString+    , sendTo+    , sendAllTo+    , recvFrom+    -- * Sending and receiving data from a buffer+    , sendBufTo+    , recvBufFrom+    ) where++import Network.Socket.ByteString.IO+import Network.Socket.Buffer+import Network.Socket.Name+import Network.Socket.Syscall+import Network.Socket.Types
+ Network/Socket/Buffer.hs view
@@ -0,0 +1,151 @@+{-# LANGUAGE CPP #-}++#include "HsNetDef.h"++module Network.Socket.Buffer (+    sendBufTo+  , sendBuf+  , recvBufFrom+  , recvBuf+  ) where++import qualified Control.Exception as E+import Foreign.Marshal.Alloc (alloca)+import GHC.IO.Exception (IOErrorType(InvalidArgument))+import System.IO.Error (mkIOError, ioeSetErrorString)++#if defined(mingw32_HOST_OS)+import GHC.IO.FD (FD(..), readRawBufferPtr, writeRawBufferPtr)+#endif++import Network.Socket.Imports+import Network.Socket.Internal+import Network.Socket.Name+import Network.Socket.Types++-- | Send data to the socket.  The recipient can be specified+-- 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.+sendBufTo :: SocketAddress sa =>+             Socket -- (possibly) bound/connected Socket+          -> Ptr a+          -> Int         -- Data to send+          -> sa+          -> IO Int      -- Number of Bytes sent+sendBufTo s ptr nbytes sa =+  withSocketAddress sa $ \p_sa siz -> fromIntegral <$> do+    fd <- fdSocket s+    let sz = fromIntegral siz+        n = fromIntegral nbytes+        flags = 0+    throwSocketErrorWaitWrite s "Network.Socket.sendBufTo" $+      c_sendto fd ptr n flags p_sa sz++#if defined(mingw32_HOST_OS)+socket2FD :: Socket -> IO FD+socket2FD s = do+  fd <- fdSocket s+  -- HACK, 1 means True+  return $ FD{ fdFD = fd, fdIsSocket_ = 1 }+#endif++-- | 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+        -> IO Int     -- Number of Bytes sent+sendBuf s str len = fromIntegral <$> do+#if defined(mingw32_HOST_OS)+-- 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.+    fd <- socket2FD s+    let clen = fromIntegral len+    throwSocketErrorIfMinus1Retry "Network.Socket.sendBuf" $+      writeRawBufferPtr "Network.Socket.sendBuf" fd (castPtr str) 0 clen+#else+    fd <- fdSocket s+    let flags = 0+        clen = fromIntegral len+    throwSocketErrorWaitWrite s "Network.Socket.sendBuf" $+      c_send fd str clen flags+#endif++-- | Receive data from the socket, writing it into buffer instead of+-- creating a new string.  The socket need not be in a connected+-- state. Returns @(nbytes, address)@ where @nbytes@ is the number of+-- bytes received and @address@ is a 'SockAddr' representing the+-- address of the sending socket.+--+-- If the first return value is zero, it means EOF.+--+-- For 'Stream' sockets, the second return value would be invalid.+--+-- NOTE: blocking on Windows unless you compile with -threaded (see+-- GHC ticket #1129)+recvBufFrom :: SocketAddress sa => Socket -> Ptr a -> Int -> IO (Int, sa)+recvBufFrom s ptr nbytes+    | nbytes <= 0 = ioError (mkInvalidRecvArgError "Network.Socket.recvBufFrom")+    | otherwise = withNewSocketAddress $ \ptr_sa sz -> alloca $ \ptr_len -> do+        fd <- fdSocket s+        poke ptr_len (fromIntegral sz)+        let cnbytes = fromIntegral nbytes+            flags = 0+        len <- throwSocketErrorWaitRead s "Network.Socket.recvBufFrom" $+                 c_recvfrom fd ptr cnbytes flags ptr_sa ptr_len+        sockaddr <- peekSocketAddress ptr_sa+            `E.catch` \(E.SomeException _) -> getPeerName s+        return (fromIntegral len, sockaddr)++-- | Receive data from the socket.  The socket must be in a connected+-- state. This function may return fewer bytes than specified.  If the+-- message is longer than the specified length, it may be discarded+-- depending on the type of socket.  This function may block until a+-- message arrives.+--+-- Considering hardware and network realities, the maximum number of+-- bytes to receive should be a small power of 2, e.g., 4096.+--+-- The return value is the length of received data. Zero means+-- EOF. Historical note: Version 2.8.x.y or earlier,+-- an EOF error was thrown. This was changed in version 3.0.+--+-- Receiving data from closed socket may lead to undefined behaviour.+recvBuf :: Socket -> Ptr Word8 -> Int -> IO Int+recvBuf s ptr nbytes+ | nbytes <= 0 = ioError (mkInvalidRecvArgError "Network.Socket.recvBuf")+ | otherwise   = do+#if defined(mingw32_HOST_OS)+-- see comment in sendBuf above.+    fd <- socket2FD s+    let cnbytes = fromIntegral nbytes+    len <- throwSocketErrorIfMinus1Retry "Network.Socket.recvBuf" $+             readRawBufferPtr "Network.Socket.recvBuf" fd ptr 0 cnbytes+#else+    fd <- fdSocket s+    len <- throwSocketErrorWaitRead s "Network.Socket.recvBuf" $+             c_recv fd (castPtr ptr) (fromIntegral nbytes) 0{-flags-}+#endif+    return $ fromIntegral len++mkInvalidRecvArgError :: String -> IOError+mkInvalidRecvArgError loc = ioeSetErrorString (mkIOError+                                    InvalidArgument+                                    loc Nothing Nothing) "non-positive length"++#if !defined(mingw32_HOST_OS)+foreign import ccall unsafe "send"+  c_send :: CInt -> Ptr a -> CSize -> CInt -> IO CInt+foreign import ccall unsafe "recv"+  c_recv :: CInt -> Ptr CChar -> CSize -> CInt -> IO CInt+#endif+foreign import CALLCONV SAFE_ON_WIN "sendto"+  c_sendto :: CInt -> Ptr a -> CSize -> CInt -> Ptr sa -> CInt -> IO CInt+foreign import CALLCONV SAFE_ON_WIN "recvfrom"+  c_recvfrom :: CInt -> Ptr a -> CSize -> CInt -> Ptr sa -> Ptr CInt -> IO CInt
+ Network/Socket/ByteString.hs view
@@ -0,0 +1,95 @@+-- |+-- Module      : Network.Socket.ByteString+-- Copyright   : (c) Johan Tibell 2007-2010+-- License     : BSD-style+--+-- Maintainer  : johan.tibell@gmail.com+-- Stability   : stable+-- Portability : portable+--+-- This module provides access to the BSD /socket/ interface.  This+-- module is generally more efficient than the 'String' based network+-- functions in 'Network.Socket'.  For detailed documentation, consult+-- your favorite POSIX socket reference. All functions communicate+-- failures by converting the error number to 'System.IO.IOError'.+--+-- This module is made to be imported with 'Network.Socket' like so:+--+-- > import Network.Socket+-- > import Network.Socket.ByteString+--+module Network.Socket.ByteString+    (+    -- * Send data to a socket+      send+    , sendAll+    , sendTo+    , sendAllTo++    -- ** Vectored I/O+    -- $vectored+    , sendMany+    , sendManyTo++    -- * Receive data from a socket+    , recv+    , recvFrom+    ) where++import Data.ByteString (ByteString)++import Network.Socket.ByteString.IO hiding (sendTo, sendAllTo, recvFrom)+import qualified Network.Socket.ByteString.IO as G+import Network.Socket.Types++-- ----------------------------------------------------------------------------+-- ** Vectored I/O++-- $vectored+--+-- Vectored I\/O, also known as scatter\/gather I\/O, allows multiple+-- data segments to be sent using a single system call, without first+-- concatenating the segments.  For example, given a list of+-- @ByteString@s, @xs@,+--+-- > sendMany sock xs+--+-- is equivalent to+--+-- > sendAll sock (concat xs)+--+-- but potentially more efficient.+--+-- Vectored I\/O are often useful when implementing network protocols+-- that, for example, group data into segments consisting of one or+-- more fixed-length headers followed by a variable-length body.++-- | Send data to the socket.  The recipient can be specified+-- 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 -> ByteString -> SockAddr -> IO Int+sendTo = G.sendTo++-- | Send data to the socket. The recipient can be specified+-- explicitly, so the socket need not be in a connected state.  Unlike+-- 'sendTo', 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.+sendAllTo :: Socket -> ByteString -> SockAddr -> IO ()+sendAllTo = G.sendAllTo++-- | 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 -> Int -> IO (ByteString, SockAddr)+recvFrom = G.recvFrom+
− Network/Socket/ByteString.hsc
@@ -1,285 +0,0 @@-{-# OPTIONS_GHC -fno-warn-warnings-deprecations #-}-{-# LANGUAGE CPP, ForeignFunctionInterface #-}-{-# LANGUAGE OverloadedStrings #-}--#include "HsNet.h"---- |--- Module      : Network.Socket.ByteString--- Copyright   : (c) Johan Tibell 2007-2010--- License     : BSD-style------ Maintainer  : johan.tibell@gmail.com--- Stability   : stable--- Portability : portable------ This module provides access to the BSD /socket/ interface.  This--- module is generally more efficient than the 'String' based network--- functions in 'Network.Socket'.  For detailed documentation, consult--- your favorite POSIX socket reference. All functions communicate--- failures by converting the error number to 'System.IO.IOError'.------ This module is made to be imported with 'Network.Socket' like so:------ > import Network.Socket hiding (send, sendTo, recv, recvFrom)--- > import Network.Socket.ByteString----module Network.Socket.ByteString-    (-    -- * Send data to a socket-      send-    , sendAll-    , sendTo-    , sendAllTo--    -- ** Vectored I/O-    -- $vectored-    , sendMany-    , sendManyTo--    -- * Receive data from a socket-    , recv-    , recvFrom-    ) where--import Control.Exception as E (catch, throwIO)-import Control.Monad (when)-import Data.ByteString (ByteString)-import Data.ByteString.Internal (createAndTrim)-import Data.ByteString.Unsafe (unsafeUseAsCStringLen)-import Foreign.Marshal.Alloc (allocaBytes)-import Foreign.Ptr (castPtr)-import Network.Socket (sendBuf, sendBufTo, recvBuf, recvBufFrom)-import System.IO.Error (isEOFError)--import qualified Data.ByteString as B--import Network.Socket.ByteString.Internal-import Network.Socket.Internal-import Network.Socket.Types--#if !defined(mingw32_HOST_OS)-import Control.Monad (liftM, zipWithM_)-import Foreign.Marshal.Array (allocaArray)-import Foreign.Marshal.Utils (with)-import Foreign.Ptr (Ptr, plusPtr)-import Foreign.Storable (Storable(..))--import Network.Socket.ByteString.IOVec (IOVec(..))-import Network.Socket.ByteString.MsgHdr (MsgHdr(..))-#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 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 ()-sendAll _    "" = return ()-sendAll sock bs = do-    sent <- send sock bs-    waitWhen0 sent sock-    when (sent >= 0) $ sendAll sock $ B.drop sent bs---- | Send data to the socket.  The recipient can be specified--- 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-       -> IO Int      -- ^ Number of bytes sent-sendTo sock xs addr =-    unsafeUseAsCStringLen xs $ \(str, len) -> sendBufTo sock str len addr---- | Send data to the socket. The recipient can be specified--- explicitly, so the socket need not be in a connected state.  Unlike--- 'sendTo', 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.-sendAllTo :: Socket      -- ^ Socket-          -> ByteString  -- ^ Data to send-          -> SockAddr    -- ^ Recipient address-          -> IO ()-sendAllTo _    "" _    = return ()-sendAllTo sock xs addr = do-    sent <- sendTo sock xs addr-    waitWhen0 sent sock-    when (sent >= 0) $ sendAllTo sock (B.drop sent xs) addr---- ------------------------------------------------------------------------------- ** Vectored I/O---- $vectored------ Vectored I\/O, also known as scatter\/gather I\/O, allows multiple--- data segments to be sent using a single system call, without first--- concatenating the segments.  For example, given a list of--- @ByteString@s, @xs@,------ > sendMany sock xs------ is equivalent to------ > sendAll sock (concat xs)------ but potentially more efficient.------ Vectored I\/O are often useful when implementing network protocols--- that, for example, group data into segments consisting of one or--- more fixed-length headers followed by a variable-length body.---- | Send data to the socket.  The socket must be in a connected--- state.  The data is sent as if the parts have been concatenated.--- 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.-sendMany :: Socket        -- ^ Connected socket-         -> [ByteString]  -- ^ Data to send-         -> IO ()-#if !defined(mingw32_HOST_OS)-sendMany _                          [] = return ()-sendMany sock@(MkSocket fd _ _ _ _) cs = do-    sent <- sendManyInner-    waitWhen0 sent sock-    when (sent >= 0) $ sendMany sock (remainingChunks sent cs)-  where-    sendManyInner =-      liftM fromIntegral . withIOVec cs $ \(iovsPtr, iovsLen) ->-          throwSocketErrorWaitWrite sock "Network.Socket.ByteString.sendMany" $-              c_writev (fromIntegral fd) iovsPtr-              (fromIntegral (min iovsLen (#const IOV_MAX)))-#else-sendMany sock = sendAll sock . B.concat-#endif---- | Send data to the socket.  The recipient can be specified--- explicitly, so the socket need not be in a connected state.  The--- data is sent as if the parts have been concatenated.  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.-sendManyTo :: Socket        -- ^ Socket-           -> [ByteString]  -- ^ Data to send-           -> SockAddr      -- ^ Recipient address-           -> IO ()-#if !defined(mingw32_HOST_OS)-sendManyTo _                          [] _    = return ()-sendManyTo sock@(MkSocket fd _ _ _ _) cs addr = do-    sent <- liftM fromIntegral sendManyToInner-    waitWhen0 sent sock-    when (sent >= 0) $ sendManyTo sock (remainingChunks sent cs) addr-  where-    sendManyToInner =-      withSockAddr addr $ \addrPtr addrSize ->-        withIOVec cs $ \(iovsPtr, iovsLen) -> do-          let msgHdr = MsgHdr-                addrPtr (fromIntegral addrSize)-                iovsPtr (fromIntegral iovsLen)-          with msgHdr $ \msgHdrPtr ->-            throwSocketErrorWaitWrite sock "Network.Socket.ByteString.sendManyTo" $-              c_sendmsg (fromIntegral fd) msgHdrPtr 0-#else-sendManyTo sock cs = sendAllTo sock (B.concat cs)-#endif---- ------------------------------------------------------------------------------- Receiving---- | Receive data from the socket.  The socket must be in a connected--- state.  This function may return fewer bytes than specified.  If--- the message is longer than the specified length, it may be--- discarded depending on the type of socket.  This function may block--- until a message arrives.------ Considering hardware and network realities, the maximum number of bytes to--- receive should be a small power of 2, e.g., 4096.------ 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 $ \ptr ->-        E.catch-          (recvBuf sock ptr nbytes)-          (\e -> if isEOFError e then return 0 else throwIO e)---- | 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-recvFrom sock nbytes =-    allocaBytes nbytes $ \ptr -> do-        (len, sockaddr) <- recvBufFrom sock ptr nbytes-        str <- B.packCStringLen (ptr, len)-        return (str, sockaddr)---- ------------------------------------------------------------------------------- Not exported--#if !defined(mingw32_HOST_OS)--- | Suppose we try to transmit a list of chunks @cs@ via a gathering write--- operation and find that @n@ bytes were sent. Then @remainingChunks n cs@ is--- list of chunks remaining to be sent.-remainingChunks :: Int -> [ByteString] -> [ByteString]-remainingChunks _ [] = []-remainingChunks i (x:xs)-    | i < len        = B.drop i x : xs-    | otherwise      = let i' = i - len in i' `seq` remainingChunks i' xs-  where-    len = B.length x---- | @withIOVec cs f@ executes the computation @f@, passing as argument a pair--- consisting of a pointer to a temporarily allocated array of pointers to--- IOVec made from @cs@ and the number of pointers (@length cs@).--- /Unix only/.-withIOVec :: [ByteString] -> ((Ptr IOVec, Int) -> IO a) -> IO a-withIOVec cs f =-    allocaArray csLen $ \aPtr -> do-        zipWithM_ pokeIov (ptrs aPtr) cs-        f (aPtr, csLen)-  where-    csLen = length cs-    ptrs = iterate (`plusPtr` sizeOf (undefined :: IOVec))-    pokeIov ptr s =-        unsafeUseAsCStringLen s $ \(sPtr, sLen) ->-        poke ptr $ IOVec sPtr (fromIntegral sLen)-#endif
+ Network/Socket/ByteString/IO.hsc view
@@ -0,0 +1,271 @@+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE OverloadedStrings #-}++#include "HsNet.h"++-- |+-- Module      : Network.Socket.ByteString+-- Copyright   : (c) Johan Tibell 2007-2010+-- License     : BSD-style+--+-- Maintainer  : johan.tibell@gmail.com+-- Stability   : stable+-- Portability : portable+--+-- This module provides access to the BSD /socket/ interface.  This+-- module is generally more efficient than the 'String' based network+-- functions in 'Network.Socket'.  For detailed documentation, consult+-- your favorite POSIX socket reference. All functions communicate+-- failures by converting the error number to 'System.IO.IOError'.+--+-- This module is made to be imported with 'Network.Socket' like so:+--+-- > import Network.Socket hiding (send, sendTo, recv, recvFrom)+-- > import Network.Socket.ByteString+--+module Network.Socket.ByteString.IO+    (+    -- * Send data to a socket+      send+    , sendAll+    , sendTo+    , sendAllTo++    -- ** Vectored I/O+    -- $vectored+    , sendMany+    , sendManyTo++    -- * Receive data from a socket+    , recv+    , recvFrom+    , waitWhen0+    ) where++import Control.Concurrent (threadWaitWrite, rtsSupportsBoundThreads)+import Data.ByteString (ByteString)+import qualified Data.ByteString as B+import Data.ByteString.Internal (createAndTrim)+import Data.ByteString.Unsafe (unsafeUseAsCStringLen)+import Foreign.Marshal.Alloc (allocaBytes)+import Foreign.Ptr (castPtr)++import Network.Socket.Buffer+import Network.Socket.ByteString.Internal+import Network.Socket.Imports+import Network.Socket.Types++#if !defined(mingw32_HOST_OS)+import Control.Monad (zipWithM_)+import Foreign.Marshal.Array (allocaArray)+import Foreign.Marshal.Utils (with)+import Foreign.Ptr (Ptr, plusPtr)+import Foreign.Storable (Storable(..))+import Network.Socket.Internal++import Network.Socket.ByteString.IOVec (IOVec(..))+import Network.Socket.ByteString.MsgHdr (MsgHdr(..))+#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 s xs = unsafeUseAsCStringLen xs $ \(str, len) ->+    sendBuf s (castPtr str) len++waitWhen0 :: Int -> Socket -> IO ()+waitWhen0 0 s = when rtsSupportsBoundThreads $ do+  fd <- fromIntegral <$> fdSocket s+  threadWaitWrite fd+waitWhen0 _ _ = return ()++-- | 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 ()+sendAll _ "" = return ()+sendAll s bs = do+    sent <- send s bs+    waitWhen0 sent s+    when (sent >= 0) $ sendAll s $ B.drop sent bs++-- | Send data to the socket.  The recipient can be specified+-- 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 :: SocketAddress sa =>+          Socket     -- ^ Socket+       -> ByteString  -- ^ Data to send+       -> sa    -- ^ Recipient address+       -> IO Int      -- ^ Number of bytes sent+sendTo s xs sa =+    unsafeUseAsCStringLen xs $ \(str, len) -> sendBufTo s str len sa++-- | Send data to the socket. The recipient can be specified+-- explicitly, so the socket need not be in a connected state.  Unlike+-- 'sendTo', 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.+sendAllTo :: SocketAddress sa =>+             Socket     -- ^ Socket+          -> ByteString  -- ^ Data to send+          -> sa    -- ^ Recipient address+          -> IO ()+sendAllTo _ "" _  = return ()+sendAllTo s xs sa = do+    sent <- sendTo s xs sa+    waitWhen0 sent s+    when (sent >= 0) $ sendAllTo s (B.drop sent xs) sa++-- | Send data to the socket.  The socket must be in a connected+-- state.  The data is sent as if the parts have been concatenated.+-- 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.+sendMany :: Socket       -- ^ Connected socket+         -> [ByteString]  -- ^ Data to send+         -> IO ()+#if !defined(mingw32_HOST_OS)+sendMany _ [] = return ()+sendMany s cs = do+    sent <- sendManyInner+    waitWhen0 sent s+    when (sent >= 0) $ sendMany s $ remainingChunks sent cs+  where+    sendManyInner =+      fmap fromIntegral . withIOVec cs $ \(iovsPtr, iovsLen) -> do+          fd <- fdSocket s+          let len =  fromIntegral $ min iovsLen (#const IOV_MAX)+          throwSocketErrorWaitWrite s "Network.Socket.ByteString.sendMany" $+              c_writev fd iovsPtr len+#else+sendMany s = sendAll s . B.concat+#endif++-- | Send data to the socket.  The recipient can be specified+-- explicitly, so the socket need not be in a connected state.  The+-- data is sent as if the parts have been concatenated.  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.+sendManyTo :: Socket       -- ^ Socket+           -> [ByteString]  -- ^ Data to send+           -> SockAddr      -- ^ Recipient address+           -> IO ()+#if !defined(mingw32_HOST_OS)+sendManyTo _ [] _    = return ()+sendManyTo s cs addr = do+    sent <- fromIntegral <$> sendManyToInner+    waitWhen0 sent s+    when (sent >= 0) $ sendManyTo s (remainingChunks sent cs) addr+  where+    sendManyToInner =+      withSockAddr addr $ \addrPtr addrSize ->+        withIOVec cs $ \(iovsPtr, iovsLen) -> do+          let msgHdr = MsgHdr+                addrPtr (fromIntegral addrSize)+                iovsPtr (fromIntegral iovsLen)+          fd <- fdSocket s+          with msgHdr $ \msgHdrPtr ->+            throwSocketErrorWaitWrite s "Network.Socket.ByteString.sendManyTo" $+              c_sendmsg fd msgHdrPtr 0+#else+sendManyTo s cs = sendAllTo s (B.concat cs)+#endif++-- ----------------------------------------------------------------------------+-- Receiving++-- | Receive data from the socket.  The socket must be in a connected+-- state.  This function may return fewer bytes than specified.  If+-- the message is longer than the specified length, it may be+-- discarded depending on the type of socket.  This function may block+-- until a message arrives.+--+-- Considering hardware and network realities, the maximum number of bytes to+-- receive should be a small power of 2, e.g., 4096.+--+-- 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 s nbytes+    | nbytes < 0 = ioError (mkInvalidRecvArgError "Network.Socket.ByteString.recv")+    | otherwise  = createAndTrim nbytes $ \ptr -> recvBuf s 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.+--+-- If the first return value is zero, it means EOF.+--+-- Receiving data from closed socket may lead to undefined behaviour.+recvFrom :: SocketAddress sa =>+            Socket                     -- ^ Socket+         -> Int                        -- ^ Maximum number of bytes to receive+         -> IO (ByteString, sa)  -- ^ Data received and sender address+recvFrom sock nbytes =+    allocaBytes nbytes $ \ptr -> do+        (len, sockaddr) <- recvBufFrom sock ptr nbytes+        str <- B.packCStringLen (ptr, len)+        return (str, sockaddr)++-- ----------------------------------------------------------------------------+-- Not exported++#if !defined(mingw32_HOST_OS)+-- | Suppose we try to transmit a list of chunks @cs@ via a gathering write+-- operation and find that @n@ bytes were sent. Then @remainingChunks n cs@ is+-- list of chunks remaining to be sent.+remainingChunks :: Int -> [ByteString] -> [ByteString]+remainingChunks _ [] = []+remainingChunks i (x:xs)+    | i < len        = B.drop i x : xs+    | otherwise      = let i' = i - len in i' `seq` remainingChunks i' xs+  where+    len = B.length x++-- | @withIOVec cs f@ executes the computation @f@, passing as argument a pair+-- consisting of a pointer to a temporarily allocated array of pointers to+-- IOVec made from @cs@ and the number of pointers (@length cs@).+-- /Unix only/.+withIOVec :: [ByteString] -> ((Ptr IOVec, Int) -> IO a) -> IO a+withIOVec cs f =+    allocaArray csLen $ \aPtr -> do+        zipWithM_ pokeIov (ptrs aPtr) cs+        f (aPtr, csLen)+  where+    csLen = length cs+    ptrs = iterate (`plusPtr` sizeOf (undefined :: IOVec))+    pokeIov ptr s =+        unsafeUseAsCStringLen s $ \(sPtr, sLen) ->+        poke ptr $ IOVec sPtr (fromIntegral sLen)+#endif
Network/Socket/ByteString/IOVec.hsc view
@@ -5,9 +5,7 @@     ( IOVec(..)     ) where -import Foreign.C.Types (CChar, CInt, CSize)-import Foreign.Ptr (Ptr)-import Foreign.Storable (Storable(..))+import Network.Socket.Imports  #include <sys/types.h> #include <sys/uio.h>
Network/Socket/ByteString/Internal.hs view
@@ -1,4 +1,4 @@-{-# LANGUAGE CPP, ForeignFunctionInterface #-}+{-# LANGUAGE CPP #-}  -- | -- Module      : Network.Socket.ByteString.Internal@@ -16,25 +16,19 @@     , c_writev     , c_sendmsg #endif-    , waitWhen0     ) where +import GHC.IO.Exception (IOErrorType(..)) import System.IO.Error (ioeSetErrorString, mkIOError)  #if !defined(mingw32_HOST_OS)-import Foreign.C.Types (CInt(..)) import System.Posix.Types (CSsize(..))-import Foreign.Ptr (Ptr) +import Network.Socket.Imports import Network.Socket.ByteString.IOVec (IOVec) import Network.Socket.ByteString.MsgHdr (MsgHdr) #endif -import Control.Concurrent (threadWaitWrite, rtsSupportsBoundThreads)-import Control.Monad (when)-import GHC.IO.Exception (IOErrorType(..))-import Network.Socket.Types- mkInvalidRecvArgError :: String -> IOError mkInvalidRecvArgError loc = ioeSetErrorString (mkIOError                                     InvalidArgument@@ -47,9 +41,3 @@ foreign import ccall unsafe "sendmsg"   c_sendmsg :: CInt -> Ptr MsgHdr -> CInt -> IO CSsize #endif--waitWhen0 :: Int -> Socket -> IO ()-waitWhen0 0 s = when rtsSupportsBoundThreads $ do-  let fd = fromIntegral $ fdSocket s-  threadWaitWrite fd-waitWhen0 _ _ = return ()
Network/Socket/ByteString/Lazy.hs view
@@ -1,5 +1,4 @@ {-# LANGUAGE CPP #-}- -- | -- Module      : Network.Socket.ByteString.Lazy -- Copyright   : (c) Bryan O'Sullivan 2009@@ -17,42 +16,37 @@ -- -- This module is made to be imported with 'Network.Socket' like so: ----- > import Network.Socket hiding (send, sendTo, recv, recvFrom)+-- > import Network.Socket -- > import Network.Socket.ByteString.Lazy -- > import Prelude hiding (getContents) ---module Network.Socket.ByteString.Lazy-    (+module Network.Socket.ByteString.Lazy (     -- * Send data to a socket-      send-    , sendAll-    ,-+    send+  , sendAll     -- * Receive data from a socket-      getContents-    , recv-    ) where--import Control.Monad (liftM)-import Data.ByteString.Lazy.Internal (ByteString(..), defaultChunkSize)-import Data.Int (Int64)-import Network.Socket (Socket(..), ShutdownCmd(..), shutdown)-import Prelude hiding (getContents)-import System.IO.Unsafe (unsafeInterleaveIO)-import System.IO.Error (catchIOError)+  , getContents+  , recv+  ) where -import qualified Data.ByteString as S-import qualified Network.Socket.ByteString as N+import           Data.ByteString.Lazy.Internal (ByteString(..), defaultChunkSize)+import           Network.Socket                (ShutdownCmd (..), shutdown)+import           Prelude                       hiding (getContents)+import           System.IO.Unsafe              (unsafeInterleaveIO)  #if defined(mingw32_HOST_OS)-import Network.Socket.ByteString.Lazy.Windows (send, sendAll)+import Network.Socket.ByteString.Lazy.Windows  (send, sendAll) #else-import Network.Socket.ByteString.Lazy.Posix (send, sendAll)+import Network.Socket.ByteString.Lazy.Posix    (send, sendAll) #endif +import qualified Data.ByteString               as S+import qualified Network.Socket.ByteString     as N+import           Network.Socket.Imports+import           Network.Socket.Types+ -- ----------------------------------------------------------------------------- -- Receiving- -- | Receive data from the socket.  The socket must be in a connected -- state.  Data is received on demand, in chunks; each chunk will be -- sized to reflect the amount of data received by individual 'recv'@@ -62,16 +56,16 @@ -- more data to be received, the receiving side of the socket is shut -- down.  If there is an error and an exception is thrown, the socket -- is not shut down.-getContents :: Socket         -- ^ Connected socket-            -> IO ByteString  -- ^ Data received-getContents sock = loop where-  loop = unsafeInterleaveIO $ do-    s <- N.recv sock defaultChunkSize-    if S.null s-      then do-        shutdown sock ShutdownReceive `catchIOError` const (return ())-        return Empty-      else Chunk s `liftM` loop+getContents+    :: Socket -- ^ Connected socket+    -> IO ByteString -- ^ Data received+getContents s = loop+  where+    loop = unsafeInterleaveIO $ do+        sbs <- N.recv s defaultChunkSize+        if S.null sbs+            then shutdown s ShutdownReceive >> return Empty+            else Chunk sbs <$> loop  -- | Receive data from the socket.  The socket must be in a connected -- state.  This function may return fewer bytes than specified.  If@@ -82,10 +76,11 @@ -- 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-recv sock nbytes = chunk `liftM` N.recv sock (fromIntegral nbytes) where-  chunk k-    | S.null k  = Empty-    | otherwise = Chunk k Empty+recv+    :: Socket -- ^ Connected socket+    -> Int64 -- ^ Maximum number of bytes to receive+    -> IO ByteString -- ^ Data received+recv s nbytes = chunk <$> N.recv s (fromIntegral nbytes)+  where+    chunk k | S.null k  = Empty+            | otherwise = Chunk k Empty
Network/Socket/ByteString/Lazy/Posix.hs view
@@ -1,59 +1,58 @@-{-# OPTIONS_GHC -fno-warn-warnings-deprecations #-} {-# LANGUAGE BangPatterns #-} {-# LANGUAGE OverloadedStrings #-} -module Network.Socket.ByteString.Lazy.Posix-    (+module Network.Socket.ByteString.Lazy.Posix (     -- * Send data to a socket-      send-    , sendAll-    ) where+    send+  , sendAll+  ) where -import Control.Monad (liftM, when)-import qualified Data.ByteString.Lazy as L-import Data.ByteString.Lazy.Internal (ByteString(..))-import Data.ByteString.Unsafe (unsafeUseAsCStringLen)-import Data.Int (Int64)-import Foreign.Marshal.Array (allocaArray)-import Foreign.Ptr (plusPtr)-import Foreign.Storable (Storable(..))+import qualified Data.ByteString.Lazy               as L+import           Data.ByteString.Unsafe             (unsafeUseAsCStringLen)+import           Foreign.Marshal.Array              (allocaArray) -import Network.Socket (Socket(..))-import Network.Socket.ByteString.IOVec (IOVec(IOVec))-import Network.Socket.ByteString.Internal (c_writev, waitWhen0)-import Network.Socket.Internal+import           Network.Socket.ByteString.Internal (c_writev)+import           Network.Socket.ByteString.IO       (waitWhen0)+import           Network.Socket.ByteString.IOVec    (IOVec (IOVec))+import           Network.Socket.Imports+import           Network.Socket.Internal+import           Network.Socket.Types  -- ----------------------------------------------------------------------------- -- Sending--send :: Socket      -- ^ Connected socket-     -> ByteString  -- ^ Data to send-     -> IO Int64    -- ^ Number of bytes sent-send sock@(MkSocket fd _ _ _ _) s = do-  let cs  = take maxNumChunks (L.toChunks s)-      len = length cs-  liftM fromIntegral . allocaArray len $ \ptr ->-    withPokes cs ptr $ \niovs ->-      throwSocketErrorWaitWrite sock "writev" $-        c_writev (fromIntegral fd) ptr niovs+send+    :: Socket -- ^ Connected socket+    -> L.ByteString -- ^ Data to send+    -> IO Int64 -- ^ Number of bytes sent+send s lbs = do+    let cs  = take maxNumChunks (L.toChunks lbs)+        len = length cs+    fd <- fdSocket s+    siz <- allocaArray len $ \ptr ->+             withPokes cs ptr $ \niovs ->+               throwSocketErrorWaitWrite s "writev" $ c_writev fd ptr niovs+    return $ fromIntegral siz   where     withPokes ss p f = loop ss p 0 0-      where loop (c:cs) q k !niovs-                | k < maxNumBytes =-                    unsafeUseAsCStringLen c $ \(ptr,len) -> do-                      poke q $ IOVec ptr (fromIntegral len)-                      loop cs (q `plusPtr` sizeOf (undefined :: IOVec))-                              (k + fromIntegral len) (niovs + 1)-                | otherwise = f niovs-            loop _ _ _ niovs = f niovs-    maxNumBytes  = 4194304 :: Int  -- maximum number of bytes to transmit in one system call-    maxNumChunks = 1024    :: Int  -- maximum number of chunks to transmit in one system call+      where+        loop (c:cs) q k !niovs+            | k < maxNumBytes = unsafeUseAsCStringLen c $ \(ptr, len) -> do+                poke q $ IOVec ptr (fromIntegral len)+                loop cs+                     (q `plusPtr` sizeOf (undefined :: IOVec))+                     (k + fromIntegral len)+                     (niovs + 1)+            | otherwise = f niovs+        loop _ _ _ niovs = f niovs+    maxNumBytes  = 4194304 :: Int -- maximum number of bytes to transmit in one system call+    maxNumChunks = 1024 :: Int -- maximum number of chunks to transmit in one system call -sendAll :: Socket      -- ^ Connected socket-        -> ByteString  -- ^ Data to send-        -> IO ()-sendAll _    "" = return ()-sendAll sock bs = do-  sent <- send sock bs-  waitWhen0 (fromIntegral sent) sock-  when (sent >= 0) $ sendAll sock $ L.drop sent bs+sendAll+    :: Socket -- ^ Connected socket+    -> L.ByteString -- ^ Data to send+    -> IO ()+sendAll _ "" = return ()+sendAll s bs = do+    sent <- send s bs+    waitWhen0 (fromIntegral sent) s+    when (sent >= 0) $ sendAll s $ L.drop sent bs
Network/Socket/ByteString/Lazy/Windows.hs view
@@ -1,40 +1,35 @@-{-# LANGUAGE BangPatterns #-} {-# LANGUAGE OverloadedStrings #-} -module Network.Socket.ByteString.Lazy.Windows-    (+module Network.Socket.ByteString.Lazy.Windows (     -- * Send data to a socket-      send-    , sendAll-    ) where--import Control.Applicative ((<$>))-import Control.Monad (when)-import qualified Data.ByteString as S-import qualified Data.ByteString.Lazy as L-import Data.Int (Int64)+    send+  , sendAll+  ) where -import Network.Socket (Socket(..))+import qualified Data.ByteString           as S+import qualified Data.ByteString.Lazy      as L import qualified Network.Socket.ByteString as Socket-import Network.Socket.ByteString.Internal (waitWhen0)+import           Network.Socket.Imports+import           Network.Socket.ByteString.IO       (waitWhen0)+import           Network.Socket.Types  -- ----------------------------------------------------------------------------- -- Sending--send :: Socket        -- ^ Connected socket-     -> L.ByteString  -- ^ Data to send-     -> IO Int64      -- ^ Number of bytes sent-send sock s = do-  fromIntegral <$> case L.toChunks s of-      -- TODO: Consider doing nothing if the string is empty.-      []    -> Socket.send sock S.empty-      (x:_) -> Socket.send sock x+send+    :: Socket -- ^ Connected socket+    -> L.ByteString -- ^ Data to send+    -> IO Int64 -- ^ Number of bytes sent+send s lbs = case L.toChunks lbs of+    -- TODO: Consider doing nothing if the string is empty.+    []    -> fromIntegral <$> Socket.send s S.empty+    (x:_) -> fromIntegral <$> Socket.send s x -sendAll :: Socket        -- ^ Connected socket-        -> L.ByteString  -- ^ Data to send-        -> IO ()-sendAll _    "" = return ()-sendAll sock bs = do-  sent <- send sock bs-  waitWhen0 (fromIntegral sent) sock-  when (sent >= 0) $ sendAll sock $ L.drop sent bs+sendAll+    :: Socket -- ^ Connected socket+    -> L.ByteString -- ^ Data to send+    -> IO ()+sendAll _ "" = return ()+sendAll s bs = do+    sent <- send s bs+    waitWhen0 (fromIntegral sent) s+    when (sent >= 0) $ sendAll s $ L.drop sent bs
Network/Socket/ByteString/MsgHdr.hsc view
@@ -1,4 +1,3 @@-{-# LANGUAGE CPP #-} {-# OPTIONS_GHC -funbox-strict-fields #-}  -- | Support module for the POSIX 'sendmsg' system call.@@ -9,11 +8,9 @@ #include <sys/types.h> #include <sys/socket.h> -import Foreign.C.Types (CInt, CSize, CUInt)-import Foreign.Ptr (Ptr)-import Foreign.Storable (Storable(..))-import Network.Socket (SockAddr)+import Network.Socket.Imports import Network.Socket.Internal (zeroMemory)+import Network.Socket.Types (SockAddr)  import Network.Socket.ByteString.IOVec (IOVec) 
+ Network/Socket/Cbits.hsc view
@@ -0,0 +1,31 @@+module Network.Socket.Cbits where++#include "HsNet.h"++import Network.Socket.Imports++-- | This is the value of SOMAXCONN, typically 128.+-- 128 is good enough for normal network servers but+-- is too small for high performance servers.+maxListenQueue :: Int+maxListenQueue = #const SOMAXCONN++#if defined(mingw32_HOST_OS)+wsaNotInitialized :: CInt+wsaNotInitialized = #const WSANOTINITIALISED+#else+fGetFd :: CInt+fGetFd = #const F_GETFD+fGetFl :: CInt+fGetFl = #const F_GETFL+fdCloexec :: CInt+fdCloexec = #const FD_CLOEXEC+oNonBlock :: CInt+oNonBlock = #const O_NONBLOCK+# if defined(HAVE_ADVANCED_SOCKET_FLAGS)+sockNonBlock :: CInt+sockNonBlock = #const SOCK_NONBLOCK+sockCloexec :: CInt+sockCloexec = #const SOCK_CLOEXEC+# endif+#endif
+ Network/Socket/Fcntl.hs view
@@ -0,0 +1,60 @@+{-# LANGUAGE CPP #-}++module Network.Socket.Fcntl where++import qualified System.Posix.Internals++#if !defined(mingw32_HOST_OS)+import Network.Socket.Cbits+#endif+import Network.Socket.Imports++-- | Set the nonblocking flag on Unix.+--   On Windows, nothing is done.+setNonBlockIfNeeded :: CInt -> IO ()+setNonBlockIfNeeded fd =+    System.Posix.Internals.setNonBlockingFD fd True++-- | Set the nonblocking flag on Unix.+--   On Windows, nothing is done.+--+--   Since 2.7.0.0.+setCloseOnExecIfNeeded :: CInt -> IO ()+#if defined(mingw32_HOST_OS)+setCloseOnExecIfNeeded _ = return ()+#else+setCloseOnExecIfNeeded fd = System.Posix.Internals.setCloseOnExec fd+#endif++#if !defined(mingw32_HOST_OS)+foreign import ccall unsafe "fcntl"+  c_fcntl_read  :: CInt -> CInt -> CInt -> IO CInt+#endif++-- | Get the close_on_exec flag.+--   On Windows, this function always returns 'False'.+--+--   Since 2.7.0.0.+getCloseOnExec :: CInt -> IO Bool+#if defined(mingw32_HOST_OS)+getCloseOnExec _ = return False+#else+getCloseOnExec fd = do+    flags <- c_fcntl_read fd fGetFd 0+    let ret = flags .&. fdCloexec+    return (ret /= 0)+#endif++-- | Get the close_on_exec flag.+--   On Windows, this function always returns 'False'.+--+--   Since 2.7.0.0.+getNonBlock :: CInt -> IO Bool+#if defined(mingw32_HOST_OS)+getNonBlock _ = return False+#else+getNonBlock fd = do+    flags <- c_fcntl_read fd fGetFl 0+    let ret = flags .&. oNonBlock+    return (ret /= 0)+#endif
+ Network/Socket/Handle.hs view
@@ -0,0 +1,24 @@+module Network.Socket.Handle where++import qualified GHC.IO.Device (IODeviceType(Stream))+import GHC.IO.Handle.FD (fdToHandle')+import System.IO (IOMode(..), Handle, BufferMode(..), hSetBuffering)++import Network.Socket.Types++-- | Turns a Socket into an 'Handle'. By default, the new handle is+-- unbuffered. Use 'System.IO.hSetBuffering' to change the buffering.+--+-- Note that since a 'Handle' is automatically closed by a finalizer+-- when it is no longer referenced, you should avoid doing any more+-- operations on the 'Socket' after calling 'socketToHandle'.  To+-- close the 'Socket' after 'socketToHandle', call 'System.IO.hClose'+-- on the 'Handle'.++socketToHandle :: Socket -> IOMode -> IO Handle+socketToHandle s mode = invalidateSocket s err $ \oldfd -> do+    h <- fdToHandle' oldfd (Just GHC.IO.Device.Stream) True (show s) mode True{-bin-}+    hSetBuffering h NoBuffering+    return h+  where+    err _ = ioError $ userError $ "socketToHandle: socket is no longer valid"
+ Network/Socket/If.hs view
@@ -0,0 +1,38 @@+{-# LANGUAGE CPP #-}++#include "HsNetDef.h"++module Network.Socket.If (+    ifNameToIndex+  , ifIndexToName+  ) where++import Foreign.Marshal.Alloc (allocaBytes)++import Network.Socket.Imports++-- | Returns the index corresponding to the interface name.+--+--   Since 2.7.0.0.+ifNameToIndex :: String -> IO (Maybe Int)+ifNameToIndex ifname = do+  index <- withCString ifname c_if_nametoindex+  -- On failure zero is returned. We'll return Nothing.+  return $ if index == 0 then Nothing else Just $ fromIntegral index++-- | Returns the interface name corresponding to the index.+--+--   Since 2.7.0.0.+ifIndexToName :: Int -> IO (Maybe String)+ifIndexToName ifn = allocaBytes 16 $ \ptr -> do -- 16 == IFNAMSIZ+    r <- c_if_indextoname (fromIntegral ifn) ptr+    if r == nullPtr then+        return Nothing+      else+        Just <$> peekCString ptr++foreign import CALLCONV safe "if_nametoindex"+   c_if_nametoindex :: CString -> IO CUInt++foreign import CALLCONV safe "if_indextoname"+   c_if_indextoname :: CUInt -> CString -> IO CString
+ Network/Socket/Imports.hs view
@@ -0,0 +1,33 @@+module Network.Socket.Imports (+    module Control.Applicative+  , module Control.Monad+  , module Data.Bits+  , module Data.Int+  , module Data.List+  , module Data.Maybe+  , module Data.Monoid+  , module Data.Ord+  , module Data.Typeable+  , module Data.Word+  , module Foreign.C.String+  , module Foreign.C.Types+  , module Foreign.Ptr+  , module Foreign.Storable+  , module Numeric+  ) where++import Control.Applicative+import Control.Monad+import Data.Bits+import Data.Int+import Data.List+import Data.Maybe+import Data.Monoid+import Data.Ord+import Data.Typeable+import Data.Word+import Foreign.C.String+import Foreign.C.Types+import Foreign.Ptr+import Foreign.Storable+import Numeric
+ Network/Socket/Info.hsc view
@@ -0,0 +1,452 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE RecordWildCards #-}+{-# OPTIONS_GHC -fno-warn-orphans #-}++#include "HsNet.h"+##include "HsNetDef.h"++module Network.Socket.Info where++import Foreign.Marshal.Alloc (alloca, allocaBytes)+import Foreign.Marshal.Utils (maybeWith, with)+import GHC.IO (unsafePerformIO)+import GHC.IO.Exception (IOErrorType(NoSuchThing))+import System.IO.Error (ioeSetErrorString, mkIOError)++import Network.Socket.Imports+import Network.Socket.Internal+import Network.Socket.Types++-----------------------------------------------------------------------------++-- | 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\"@.+type HostName       = String+-- | Either a service name e.g., @\"http\"@ or a numeric port number.+type ServiceName    = String++-----------------------------------------------------------------------------+-- Address and service lookups++-- | Flags that control the querying behaviour of 'getAddrInfo'.+--   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".+    --   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)++aiFlagMapping :: [(AddrInfoFlag, CInt)]++aiFlagMapping =+    [+#if HAVE_DECL_AI_ADDRCONFIG+     (AI_ADDRCONFIG, #const AI_ADDRCONFIG),+#else+     (AI_ADDRCONFIG, 0),+#endif+#if HAVE_DECL_AI_ALL+     (AI_ALL, #const AI_ALL),+#else+     (AI_ALL, 0),+#endif+     (AI_CANONNAME, #const AI_CANONNAME),+     (AI_NUMERICHOST, #const AI_NUMERICHOST),+#if HAVE_DECL_AI_NUMERICSERV+     (AI_NUMERICSERV, #const AI_NUMERICSERV),+#else+     (AI_NUMERICSERV, 0),+#endif+     (AI_PASSIVE, #const AI_PASSIVE),+#if HAVE_DECL_AI_V4MAPPED+     (AI_V4MAPPED, #const AI_V4MAPPED)+#else+     (AI_V4MAPPED, 0)+#endif+    ]++-- | Indicate whether the given 'AddrInfoFlag' will have any effect on+-- this system.+addrInfoFlagImplemented :: AddrInfoFlag -> Bool+addrInfoFlagImplemented f = packBits aiFlagMapping [f] /= 0++data AddrInfo = AddrInfo {+    addrFlags :: [AddrInfoFlag]+  , addrFamily :: Family+  , addrSocketType :: SocketType+  , addrProtocol :: ProtocolNumber+  , addrAddress :: SockAddr+  , addrCanonName :: Maybe String+  } deriving (Eq, Show, Typeable)++instance Storable AddrInfo where+    sizeOf    _ = #const sizeof(struct addrinfo)+    alignment _ = alignment (undefined :: CInt)++    peek p = do+        ai_flags <- (#peek struct addrinfo, ai_flags) p+        ai_family <- (#peek struct addrinfo, ai_family) p+        ai_socktype <- (#peek struct addrinfo, ai_socktype) p+        ai_protocol <- (#peek struct addrinfo, ai_protocol) p+        ai_addr <- (#peek struct addrinfo, ai_addr) p >>= peekSockAddr+        ai_canonname_ptr <- (#peek struct addrinfo, ai_canonname) p++        ai_canonname <- if ai_canonname_ptr == nullPtr+                        then return Nothing+                        else Just <$> peekCString ai_canonname_ptr++        socktype <- unpackSocketType' "AddrInfo.peek" ai_socktype+        return $ AddrInfo {+            addrFlags = unpackBits aiFlagMapping ai_flags+          , addrFamily = unpackFamily ai_family+          , addrSocketType = socktype+          , addrProtocol = ai_protocol+          , addrAddress = ai_addr+          , addrCanonName = ai_canonname+          }++    poke p (AddrInfo flags family sockType protocol _ _) = do+        c_stype <- packSocketTypeOrThrow "AddrInfo.poke" sockType++        (#poke struct addrinfo, ai_flags) p (packBits aiFlagMapping flags)+        (#poke struct addrinfo, ai_family) p (packFamily family)+        (#poke struct addrinfo, ai_socktype) p c_stype+        (#poke struct addrinfo, ai_protocol) p protocol++        -- stuff below is probably not needed, but let's zero it for safety++        (#poke struct addrinfo, ai_addrlen) p (0::CSize)+        (#poke struct addrinfo, ai_addr) p nullPtr+        (#poke struct addrinfo, ai_canonname) p nullPtr+        (#poke struct addrinfo, ai_next) p nullPtr++-- | 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)++niFlagMapping :: [(NameInfoFlag, CInt)]++niFlagMapping = [(NI_DGRAM, #const NI_DGRAM),+                 (NI_NAMEREQD, #const NI_NAMEREQD),+                 (NI_NOFQDN, #const NI_NOFQDN),+                 (NI_NUMERICHOST, #const NI_NUMERICHOST),+                 (NI_NUMERICSERV, #const NI_NUMERICSERV)]++-- | 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+  , addrSocketType = NoSocketType+  , addrProtocol   = defaultProtocol+  , addrAddress    = undefined+  , addrCanonName  = undefined+  }++-- | Shows the fields of 'defaultHints', without inspecting the by-default undefined fields 'addrAddress' and 'addrCanonName'.+showDefaultHints :: AddrInfo -> String+showDefaultHints AddrInfo{..} = concat [+    "AddrInfo {"+  , "addrFlags = "+  , show addrFlags+  , ", addrFamily = "+  , show addrFamily+  , ", addrSocketType = "+  , show addrSocketType+  , ", addrProtocol = "+  , show addrProtocol+  , ", addrAddress = "+  , "<assumed to be undefined>"+  , ", addrCanonName = "+  , "<assumed to be undefined>"+  , "}"+  ]++-----------------------------------------------------------------------------+-- | Resolve a host or service name to one or more addresses.+-- The 'AddrInfo' values that this function returns contain 'SockAddr'+-- values that you can pass directly to 'connect' or+-- 'bind'.+--+-- This function is protocol independent.  It can return both IPv4 and+-- IPv6 address information.+--+-- The 'AddrInfo' argument specifies the preferred query behaviour,+-- socket options, or protocol.  You can override these conveniently+-- using Haskell's record update syntax on 'defaultHints', for example+-- as follows:+--+-- >>> 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+-- network address (dotted quad for IPv4, colon-separated hex for+-- IPv6) or a hostname.  In the latter case, its addresses will be+-- looked up unless 'AI_NUMERICHOST' is specified as a hint.  If you+-- do not provide a 'HostName' value /and/ do not set 'AI_PASSIVE' as+-- a hint, network addresses in the result will contain the address of+-- the loopback interface.+--+-- If the query fails, this function throws an IO exception instead of+-- returning an empty list.  Otherwise, it returns a non-empty list+-- of 'AddrInfo' values.+--+-- There are several reasons why a query might result in several+-- values.  For example, the queried-for host could be multihomed, or+-- the service might be available via several protocols.+--+-- Note: the order of arguments is slightly different to that defined+-- for @getaddrinfo@ in RFC 2553.  The 'AddrInfo' parameter comes first+-- to make partial application easier.+--+-- >>> 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+    -> Maybe ServiceName -- ^ service name to look up+    -> IO [AddrInfo] -- ^ resolved addresses, with "best" first+getAddrInfo hints node service = alloc getaddrinfo+  where+    alloc body = withSocketsDo $ maybeWith withCString node $ \c_node ->+        maybeWith withCString service                       $ \c_service ->+            maybeWith with filteredHints                    $ \c_hints ->+                  alloca                                    $ \ptr_ptr_addrs ->+                      body c_node c_service c_hints ptr_ptr_addrs+    getaddrinfo c_node c_service c_hints ptr_ptr_addrs = do+        ret <- c_getaddrinfo c_node c_service c_hints ptr_ptr_addrs+        if ret == 0 then do+            ptr_addrs <- peek ptr_ptr_addrs+            ais       <- followAddrInfo ptr_addrs+            c_freeaddrinfo ptr_addrs+            return ais+          else do+            err <- gai_strerror ret+            ioError $ ioeSetErrorString+                        (mkIOError NoSuchThing message Nothing Nothing)+                        err+    message = concat [+        "Network.Socket.getAddrInfo (called with preferred socket type/protocol: "+      , maybe (show hints) showDefaultHints hints+      , ", host name: "+      , show node+      , ", service name: "+      , show service+      , ")"+      ]+#if defined(darwin_HOST_OS)+    -- Leaving out the service and using AI_NUMERICSERV causes a+    -- segfault on OS X 10.8.2. This code removes AI_NUMERICSERV+    -- (which has no effect) in that case.+    toHints h = h { addrFlags = delete AI_NUMERICSERV (addrFlags h) }+    filteredHints = case service of+        Nothing -> toHints <$> hints+        _       -> hints+#else+    filteredHints = hints+#endif++followAddrInfo :: Ptr AddrInfo -> IO [AddrInfo]+followAddrInfo ptr_ai+    | ptr_ai == nullPtr = return []+    | otherwise = do+        a  <- peek ptr_ai+        as <- (# peek struct addrinfo, ai_next) ptr_ai >>= followAddrInfo+        return (a : as)++foreign import ccall safe "hsnet_getaddrinfo"+    c_getaddrinfo :: CString -> CString -> Ptr AddrInfo -> Ptr (Ptr AddrInfo)+                  -> IO CInt++foreign import ccall safe "hsnet_freeaddrinfo"+    c_freeaddrinfo :: Ptr AddrInfo -> IO ()++gai_strerror :: CInt -> IO String++#ifdef HAVE_GAI_STRERROR+gai_strerror n = c_gai_strerror n >>= peekCString++foreign import ccall safe "gai_strerror"+    c_gai_strerror :: CInt -> IO CString+#else+gai_strerror n = ioError $ userError $ "Network.Socket.gai_strerror not supported: " ++ show n+#endif++-----------------------------------------------------------------------------++withCStringIf :: Bool -> Int -> (CSize -> CString -> IO a) -> IO a+withCStringIf False _ f = f 0 nullPtr+withCStringIf True  n f = allocaBytes n (f (fromIntegral n))++-- | Resolve an address to a host or service name.+-- This function is protocol independent.+-- 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.+--+-- If the query fails, this function throws an IO exception.+--+-- >>> addr:_ <- getAddrInfo (Just defaultHints) (Just "127.0.0.1") (Just "http")+-- >>> getNameInfo [NI_NUMERICHOST, NI_NUMERICSERV] True True $ addrAddress addr+-- (Just "127.0.0.1",Just "80")+{-+-- >>> getNameInfo [] True True $ addrAddress addr+-- (Just "localhost",Just "http")+-}+getNameInfo+    :: [NameInfoFlag] -- ^ flags to control lookup behaviour+    -> Bool -- ^ whether to look up a hostname+    -> Bool -- ^ whether to look up a service name+    -> SockAddr -- ^ the address to look up+    -> IO (Maybe HostName, Maybe ServiceName)+getNameInfo flags doHost doService addr = alloc getnameinfo+  where+    alloc body = withSocketsDo $+        withCStringIf doHost (# const NI_MAXHOST)        $ \c_hostlen c_host ->+            withCStringIf doService (# const NI_MAXSERV) $ \c_servlen c_serv ->+                withSockAddr addr                        $ \ptr_addr sz ->+                  body c_hostlen c_host c_servlen c_serv ptr_addr sz+    getnameinfo c_hostlen c_host c_servlen c_serv ptr_addr sz = do+        ret <- c_getnameinfo ptr_addr+                             (fromIntegral sz)+                             c_host+                             c_hostlen+                             c_serv+                             c_servlen+                             (packBits niFlagMapping flags)+        if ret == 0 then do+            let peekIf doIf c_val =+                    if doIf then Just <$> peekCString c_val else return Nothing+            host <- peekIf doHost c_host+            serv <- peekIf doService c_serv+            return (host, serv)+          else do+            err <- gai_strerror ret+            ioError $ ioeSetErrorString+                        (mkIOError NoSuchThing message Nothing Nothing)+                        err+    message = concat [+        "Network.Socket.getNameInfo (called with flags: "+      , show flags+      , ", hostname lookup: "+      , show doHost+      , ", service name lookup: "+      , show doService+      , ", socket address: "+      , show addr+      , ")"+      ]++foreign import ccall safe "hsnet_getnameinfo"+    c_getnameinfo :: Ptr SockAddr -> CInt{-CSockLen???-} -> CString -> CSize -> CString+                  -> CSize -> CInt -> IO CInt++-- | Pack a list of values into a bitmask.  The possible mappings from+-- value to bit-to-set are given as the first argument.  We assume+-- that each value can cause exactly one bit to be set; unpackBits will+-- break if this property is not true.++-----------------------------------------------------------------------------++packBits :: (Eq a, Num b, Bits b) => [(a, b)] -> [a] -> b+packBits mapping xs = foldl' pack 0 mapping+  where+    pack acc (k, v) | k `elem` xs = acc .|. v+                    | otherwise   = acc++-- | Unpack a bitmask into a list of values.+unpackBits :: (Num b, Bits b) => [(a, b)] -> b -> [a]+-- Be permissive and ignore unknown bit values. At least on OS X,+-- getaddrinfo returns an ai_flags field with bits set that have no+-- entry in <netdb.h>.+unpackBits [] _    = []+unpackBits ((k,v):xs) r+    | r .&. v /= 0 = k : unpackBits xs (r .&. complement v)+    | otherwise    = unpackBits xs r++-----------------------------------------------------------------------------+-- SockAddr++instance Show SockAddr where+#if defined(DOMAIN_SOCKET_SUPPORT)+  showsPrec _ (SockAddrUnix str) = showString str+#else+  showsPrec _ SockAddrUnix{} = error "showsPrec: not supported"+#endif+  showsPrec _ addr@(SockAddrInet port _)+   = showString (unsafePerformIO $+                 fst <$> getNameInfo [NI_NUMERICHOST] True False addr >>=+                 maybe (fail "showsPrec: impossible internal error") return)+   . showString ":"+   . shows port+  showsPrec _ addr@(SockAddrInet6 port _ _ _)+   = showChar '['+   . showString (unsafePerformIO $+                 fst <$> getNameInfo [NI_NUMERICHOST] True False addr >>=+                 maybe (fail "showsPrec: impossible internal error") return)+   . showString "]:"+   . shows port
+ Network/Socket/Internal.hs view
@@ -0,0 +1,244 @@+{-# LANGUAGE CPP #-}+{-# OPTIONS_GHC -fno-warn-orphans #-}++#include "HsNetDef.h"++-----------------------------------------------------------------------------+-- |+-- Module      :  Network.Socket.Internal+-- Copyright   :  (c) The University of Glasgow 2001+-- License     :  BSD-style (see the file libraries/network/LICENSE)+--+-- Maintainer  :  libraries@haskell.org+-- Stability   :  provisional+-- Portability :  portable+--+-- A module containing semi-public 'Network.Socket' internals.+-- Modules which extend the 'Network.Socket' module will need to use+-- this module while ideally most users will be able to make do with+-- the public interface.+--+-----------------------------------------------------------------------------++module Network.Socket.Internal+    (+    -- * Socket error functions+      throwSocketError+    , throwSocketErrorCode+#if defined(mingw32_HOST_OS)+    , c_getLastError+#endif++    -- * Guards for socket operations that may fail+    , throwSocketErrorIfMinus1_+    , throwSocketErrorIfMinus1Retry+    , throwSocketErrorIfMinus1Retry_+    , throwSocketErrorIfMinus1RetryMayBlock++    -- ** Guards that wait and retry if the operation would block+    -- | These guards are based on 'throwSocketErrorIfMinus1RetryMayBlock'.+    -- They wait for socket readiness if the action fails with @EWOULDBLOCK@+    -- or similar.+    , throwSocketErrorWaitRead+    , throwSocketErrorWaitWrite++    -- * Initialization+    , withSocketsDo++    -- * Low-level helpers+    , zeroMemory+    ) where++import GHC.Conc (threadWaitRead, threadWaitWrite)++#if defined(mingw32_HOST_OS)+import Control.Exception (evaluate)+import System.IO.Unsafe (unsafePerformIO)+# if __GLASGOW_HASKELL__ >= 707+import GHC.IO.Exception (IOErrorType(..))+# else+import GHC.IOBase (IOErrorType(..))+# endif+import System.IO.Error (ioeSetErrorString, mkIOError)+#else+import Foreign.C.Error (throwErrno, throwErrnoIfMinus1Retry,+                        throwErrnoIfMinus1RetryMayBlock, throwErrnoIfMinus1_,+                        Errno(..), errnoToIOError)+#endif++#if defined(mingw32_HOST_OS)+import Network.Socket.Cbits+#endif+import Network.Socket.Imports+import Network.Socket.Types++-- ---------------------------------------------------------------------+-- Guards for socket operations that may fail++-- | Throw an 'IOError' corresponding to the current socket error.+throwSocketError :: String  -- ^ textual description of the error location+                 -> IO a++-- | Like 'throwSocketError', but the error code is supplied as an argument.+--+-- On Windows, do not use errno.  Use a system error code instead.+throwSocketErrorCode :: String -> CInt -> IO a++-- | Throw an 'IOError' corresponding to the current socket error if+-- the IO action returns a result of @-1@.  Discards the result of the+-- IO action after error handling.+throwSocketErrorIfMinus1_+    :: (Eq a, Num a)+    => String  -- ^ textual description of the location+    -> IO a    -- ^ the 'IO' operation to be executed+    -> IO ()++{-# SPECIALIZE throwSocketErrorIfMinus1_ :: String -> IO CInt -> IO () #-}++-- | Throw an 'IOError' corresponding to the current socket error if+-- the IO action returns a result of @-1@, but retries in case of an+-- interrupted operation.+throwSocketErrorIfMinus1Retry+    :: (Eq a, Num a)+    => String  -- ^ textual description of the location+    -> IO a    -- ^ the 'IO' operation to be executed+    -> IO a++{-# SPECIALIZE throwSocketErrorIfMinus1Retry :: String -> IO CInt -> IO CInt #-}++-- | Throw an 'IOError' corresponding to the current socket error if+-- the IO action returns a result of @-1@, but retries in case of an+-- interrupted operation. Discards the result of the IO action after+-- error handling.+throwSocketErrorIfMinus1Retry_+    :: (Eq a, Num a)+    => String  -- ^ textual description of the location+    -> IO a    -- ^ the 'IO' operation to be executed+    -> IO ()+throwSocketErrorIfMinus1Retry_ loc m =+    void $ throwSocketErrorIfMinus1Retry loc m+{-# SPECIALIZE throwSocketErrorIfMinus1Retry_ :: String -> IO CInt -> IO () #-}++-- | Throw an 'IOError' corresponding to the current socket error if+-- the IO action returns a result of @-1@, but retries in case of an+-- interrupted operation.  Checks for operations that would block and+-- executes an alternative action before retrying in that case.+throwSocketErrorIfMinus1RetryMayBlock+    :: (Eq a, Num a)+    => String  -- ^ textual description of the location+    -> IO b    -- ^ action to execute before retrying if an+               --   immediate retry would block+    -> IO a    -- ^ the 'IO' operation to be executed+    -> IO a++{-# SPECIALIZE throwSocketErrorIfMinus1RetryMayBlock+        :: String -> IO b -> IO CInt -> IO CInt #-}++#if defined(mingw32_HOST_OS)++throwSocketErrorIfMinus1RetryMayBlock name _ act+  = throwSocketErrorIfMinus1Retry name act++throwSocketErrorIfMinus1_ name act = do+  _ <- throwSocketErrorIfMinus1Retry name act+  return ()++throwSocketErrorIfMinus1Retry name act = do+  r <- act+  if (r == -1)+   then do+    rc <- c_getLastError+    if rc == wsaNotInitialized then do+        withSocketsDo (return ())+        r' <- act+        if (r' == -1)+           then throwSocketError name+           else return r'+      else+        throwSocketError name+   else return r++throwSocketErrorCode name rc = do+    pstr <- c_getWSError rc+    str  <- peekCString pstr+    ioError (ioeSetErrorString (mkIOError OtherError name Nothing Nothing) str)++throwSocketError name =+    c_getLastError >>= throwSocketErrorCode name++foreign import CALLCONV unsafe "WSAGetLastError"+  c_getLastError :: IO CInt++foreign import ccall unsafe "getWSErrorDescr"+  c_getWSError :: CInt -> IO (Ptr CChar)++#else++throwSocketErrorIfMinus1RetryMayBlock name on_block act =+    throwErrnoIfMinus1RetryMayBlock name act on_block++throwSocketErrorIfMinus1Retry = throwErrnoIfMinus1Retry++throwSocketErrorIfMinus1_ = throwErrnoIfMinus1_++throwSocketError = throwErrno++throwSocketErrorCode loc errno =+    ioError (errnoToIOError loc (Errno errno) Nothing Nothing)++#endif++-- | Like 'throwSocketErrorIfMinus1Retry', but if the action fails with+-- @EWOULDBLOCK@ or similar, wait for the socket to be read-ready,+-- and try again.+throwSocketErrorWaitRead :: (Eq a, Num a) => Socket -> String -> IO a -> IO a+throwSocketErrorWaitRead s name io = do+    fd <- fromIntegral <$> fdSocket s+    throwSocketErrorIfMinus1RetryMayBlock name (threadWaitRead fd) io++-- | Like 'throwSocketErrorIfMinus1Retry', but if the action fails with+-- @EWOULDBLOCK@ or similar, wait for the socket to be write-ready,+-- and try again.+throwSocketErrorWaitWrite :: (Eq a, Num a) => Socket -> String -> IO a -> IO a+throwSocketErrorWaitWrite s name io = do+    fd <- fromIntegral <$> fdSocket s+    throwSocketErrorIfMinus1RetryMayBlock name (threadWaitWrite fd) io++-- ---------------------------------------------------------------------------+-- WinSock support++{-| With older versions of the @network@ library (version 2.6.0.2 or earlier)+on Windows operating systems,+the networking subsystem must be initialised using 'withSocketsDo' before+any networking operations can be used. eg.++> main = withSocketsDo $ do {...}++It is fine to nest calls to 'withSocketsDo', and to perform networking operations+after 'withSocketsDo' has returned.++'withSocketsDo' is not necessary for the current network library.+However, for compatibility with older versions on Windows, it is good practice+to always call 'withSocketsDo' (it's very cheap).+-}+{-# INLINE withSocketsDo #-}+withSocketsDo :: IO a -> IO a+#if defined(mingw32_HOST_OS)++withSocketsDo act = evaluate withSocketsInit >> act++{-# NOINLINE withSocketsInit #-}+withSocketsInit :: ()+-- Use a CAF to make forcing it do initialisation once, but subsequent forces will be cheap+withSocketsInit = unsafePerformIO $ do+    x <- initWinSock+    when (x /= 0) $ ioError $+      userError "Network.Socket.Internal.withSocketsDo: Failed to initialise WinSock"++foreign import ccall unsafe "initWinSock" initWinSock :: IO Int++#else++withSocketsDo x = x++#endif
− Network/Socket/Internal.hsc
@@ -1,277 +0,0 @@-{-# LANGUAGE CPP #-}-{-# LANGUAGE ForeignFunctionInterface #-}-{-# OPTIONS_GHC -fno-warn-orphans #-}--------------------------------------------------------------------------------- |--- Module      :  Network.Socket.Internal--- Copyright   :  (c) The University of Glasgow 2001--- License     :  BSD-style (see the file libraries/network/LICENSE)------ Maintainer  :  libraries@haskell.org--- Stability   :  provisional--- Portability :  portable------ A module containing semi-public 'Network.Socket' internals.--- Modules which extend the 'Network.Socket' module will need to use--- this module while ideally most users will be able to make do with--- the public interface.-----------------------------------------------------------------------------------#include "HsNet.h"-##include "HsNetDef.h"--module Network.Socket.Internal-    (-    -- * Socket addresses-      HostAddress-#if defined(IPV6_SOCKET_SUPPORT)-    , HostAddress6-    , FlowInfo-    , ScopeID-#endif-    , PortNumber(..)-    , SockAddr(..)--    , peekSockAddr-    , pokeSockAddr-    , sizeOfSockAddr-    , sizeOfSockAddrByFamily-    , withSockAddr-    , withNewSockAddr--    -- * Protocol families-    , Family(..)--    -- * Socket error functions-#if defined(HAVE_WINSOCK2_H)-    , c_getLastError-#endif-    , throwSocketError-    , throwSocketErrorCode--    -- * Guards for socket operations that may fail-    , throwSocketErrorIfMinus1_-    , throwSocketErrorIfMinus1Retry-    , throwSocketErrorIfMinus1Retry_-    , throwSocketErrorIfMinus1RetryMayBlock--    -- ** Guards that wait and retry if the operation would block-    -- | These guards are based on 'throwSocketErrorIfMinus1RetryMayBlock'.-    -- They wait for socket readiness if the action fails with @EWOULDBLOCK@-    -- or similar.-    , throwSocketErrorWaitRead-    , throwSocketErrorWaitWrite--    -- * Initialization-    , withSocketsDo--    -- * Low-level helpers-    , zeroMemory-    ) where--import Foreign.C.Error (throwErrno, throwErrnoIfMinus1Retry,-                        throwErrnoIfMinus1RetryMayBlock, throwErrnoIfMinus1_,-                        Errno(..), errnoToIOError)-#if defined(HAVE_WINSOCK2_H)-import Foreign.C.String (peekCString)-import Foreign.Ptr (Ptr)-#endif-import Foreign.C.Types (CInt(..))-import GHC.Conc (threadWaitRead, threadWaitWrite)--#if defined(HAVE_WINSOCK2_H)-import Control.Exception ( evaluate )-import System.IO.Unsafe ( unsafePerformIO )-import Control.Monad ( when )-#  if __GLASGOW_HASKELL__ >= 707-import GHC.IO.Exception ( IOErrorType(..) )-#  else-import GHC.IOBase ( IOErrorType(..) )-#  endif-import Foreign.C.Types ( CChar )-import System.IO.Error ( ioeSetErrorString, mkIOError )-#endif--import Network.Socket.Types---- ------------------------------------------------------------------------ Guards for socket operations that may fail---- | Throw an 'IOError' corresponding to the current socket error.-throwSocketError :: String  -- ^ textual description of the error location-                 -> IO a---- | Like 'throwSocketError', but the error code is supplied as an argument.------ On Windows, do not use errno.  Use a system error code instead.-throwSocketErrorCode :: String -> CInt -> IO a---- | Throw an 'IOError' corresponding to the current socket error if--- the IO action returns a result of @-1@.  Discards the result of the--- IO action after error handling.-throwSocketErrorIfMinus1_-    :: (Eq a, Num a)-    => String  -- ^ textual description of the location-    -> IO a    -- ^ the 'IO' operation to be executed-    -> IO ()--{-# SPECIALIZE throwSocketErrorIfMinus1_ :: String -> IO CInt -> IO () #-}---- | Throw an 'IOError' corresponding to the current socket error if--- the IO action returns a result of @-1@, but retries in case of an--- interrupted operation.-throwSocketErrorIfMinus1Retry-    :: (Eq a, Num a)-    => String  -- ^ textual description of the location-    -> IO a    -- ^ the 'IO' operation to be executed-    -> IO a--{-# SPECIALIZE throwSocketErrorIfMinus1Retry :: String -> IO CInt -> IO CInt #-}---- | Throw an 'IOError' corresponding to the current socket error if--- the IO action returns a result of @-1@, but retries in case of an--- interrupted operation. Discards the result of the IO action after--- error handling.-throwSocketErrorIfMinus1Retry_-    :: (Eq a, Num a)-    => String  -- ^ textual description of the location-    -> IO a    -- ^ the 'IO' operation to be executed-    -> IO ()-throwSocketErrorIfMinus1Retry_ loc m =-    throwSocketErrorIfMinus1Retry loc m >> return ()-{-# SPECIALIZE throwSocketErrorIfMinus1Retry_ :: String -> IO CInt -> IO () #-}---- | Throw an 'IOError' corresponding to the current socket error if--- the IO action returns a result of @-1@, but retries in case of an--- interrupted operation.  Checks for operations that would block and--- executes an alternative action before retrying in that case.-throwSocketErrorIfMinus1RetryMayBlock-    :: (Eq a, Num a)-    => String  -- ^ textual description of the location-    -> IO b    -- ^ action to execute before retrying if an-               --   immediate retry would block-    -> IO a    -- ^ the 'IO' operation to be executed-    -> IO a--{-# SPECIALIZE throwSocketErrorIfMinus1RetryMayBlock-        :: String -> IO b -> IO CInt -> IO CInt #-}--#if (!defined(HAVE_WINSOCK2_H))--throwSocketErrorIfMinus1RetryMayBlock name on_block act =-    throwErrnoIfMinus1RetryMayBlock name act on_block--throwSocketErrorIfMinus1Retry = throwErrnoIfMinus1Retry--throwSocketErrorIfMinus1_ = throwErrnoIfMinus1_--throwSocketError = throwErrno--throwSocketErrorCode loc errno =-    ioError (errnoToIOError loc (Errno errno) Nothing Nothing)--#else--throwSocketErrorIfMinus1RetryMayBlock name _ act-  = throwSocketErrorIfMinus1Retry name act--throwSocketErrorIfMinus1_ name act = do-  throwSocketErrorIfMinus1Retry name act-  return ()--# if defined(HAVE_WINSOCK2_H)-throwSocketErrorIfMinus1Retry name act = do-  r <- act-  if (r == -1)-   then do-    rc   <- c_getLastError-    case rc of-      #{const WSANOTINITIALISED} -> do-        withSocketsDo (return ())-        r <- act-        if (r == -1)-           then throwSocketError name-           else return r-      _ -> throwSocketError name-   else return r--throwSocketErrorCode name rc = do-    pstr <- c_getWSError rc-    str  <- peekCString pstr-    ioError (ioeSetErrorString (mkIOError OtherError name Nothing Nothing) str)--throwSocketError name =-    c_getLastError >>= throwSocketErrorCode name--foreign import CALLCONV unsafe "WSAGetLastError"-  c_getLastError :: IO CInt--foreign import ccall unsafe "getWSErrorDescr"-  c_getWSError :: CInt -> IO (Ptr CChar)---# else-throwSocketErrorIfMinus1Retry = throwErrnoIfMinus1Retry-throwSocketError = throwErrno-throwSocketErrorCode loc errno =-    ioError (errnoToIOError loc (Errno errno) Nothing Nothing)-# endif-#endif---- | Like 'throwSocketErrorIfMinus1Retry', but if the action fails with--- @EWOULDBLOCK@ or similar, wait for the socket to be read-ready,--- and try again.-throwSocketErrorWaitRead :: (Eq a, Num a) => Socket -> String -> IO a -> IO a-throwSocketErrorWaitRead sock name io =-    throwSocketErrorIfMinus1RetryMayBlock name-        (threadWaitRead $ fromIntegral $ fdSocket sock)-        io---- | Like 'throwSocketErrorIfMinus1Retry', but if the action fails with--- @EWOULDBLOCK@ or similar, wait for the socket to be write-ready,--- and try again.-throwSocketErrorWaitWrite :: (Eq a, Num a) => Socket -> String -> IO a -> IO a-throwSocketErrorWaitWrite sock name io =-    throwSocketErrorIfMinus1RetryMayBlock name-        (threadWaitWrite $ fromIntegral $ fdSocket sock)-        io---- ------------------------------------------------------------------------------ WinSock support--{-| With older versions of the @network@ library (version 2.6.0.2 or earlier)-on Windows operating systems,-the networking subsystem must be initialised using 'withSocketsDo' before-any networking operations can be used. eg.--> main = withSocketsDo $ do {...}--It is fine to nest calls to 'withSocketsDo', and to perform networking operations-after 'withSocketsDo' has returned.--In newer versions of the @network@ library (version v2.6.1.0 or later)-it is only necessary to call-'withSocketsDo' if you are calling the 'MkSocket' constructor directly.-However, for compatibility with older versions on Windows, it is good practice-to always call 'withSocketsDo' (it's very cheap).--}-{-# INLINE withSocketsDo #-}-withSocketsDo :: IO a -> IO a-#if !defined(WITH_WINSOCK)-withSocketsDo x = x-#else-withSocketsDo act = evaluate withSocketsInit >> act---{-# NOINLINE withSocketsInit #-}-withSocketsInit :: ()--- Use a CAF to make forcing it do initialisation once, but subsequent forces will be cheap-withSocketsInit = unsafePerformIO $ do-    x <- initWinSock-    when (x /= 0) $ ioError $-      userError "Network.Socket.Internal.withSocketsDo: Failed to initialise WinSock"--foreign import ccall unsafe "initWinSock" initWinSock :: IO Int--#endif
+ Network/Socket/Name.hs view
@@ -0,0 +1,72 @@+{-# LANGUAGE CPP #-}++#include "HsNetDef.h"++module Network.Socket.Name (+    getPeerName+  , getSocketName+  , socketPort+  , socketPortSafe+  ) where++import Foreign.Marshal.Utils (with)++import Network.Socket.Imports+import Network.Socket.Internal+import Network.Socket.Types++-- | Getting peer's socket address.+getPeerName :: SocketAddress sa => Socket -> IO sa+getPeerName s =+ withNewSocketAddress $ \ptr sz ->+   with (fromIntegral sz) $ \int_star -> do+     fd <- fdSocket s+     throwSocketErrorIfMinus1Retry_ "Network.Socket.getPeerName" $+       c_getpeername fd ptr int_star+     _sz <- peek int_star+     peekSocketAddress ptr++-- | Getting my socket address.+getSocketName :: SocketAddress sa => Socket -> IO sa+getSocketName s =+ withNewSocketAddress $ \ptr sz ->+   with (fromIntegral sz) $ \int_star -> do+     fd <- fdSocket s+     throwSocketErrorIfMinus1Retry_ "Network.Socket.getSocketName" $+       c_getsockname fd ptr int_star+     peekSocketAddress ptr++foreign import CALLCONV unsafe "getpeername"+  c_getpeername :: CInt -> Ptr sa -> Ptr CInt -> IO CInt+foreign import CALLCONV unsafe "getsockname"+  c_getsockname :: CInt -> Ptr sa -> Ptr CInt -> IO CInt++-- ---------------------------------------------------------------------------+-- socketPort+--+-- The port number the given socket is currently connected to can be+-- determined by calling $port$, is generally only useful when bind+-- was given $aNY\_PORT$.++-- | Getting the port of socket.+--   `IOError` is thrown if a port is not available.+socketPort :: Socket            -- Connected & Bound Socket+           -> IO PortNumber     -- Port Number of Socket+socketPort s = do+    sa <- getSocketName s+    case sa of+      SockAddrInet port _      -> return port+      SockAddrInet6 port _ _ _ -> return port+      _                        -> ioError $ userError "Network.Socket.socketPort: AF_UNIX not supported."++-- ---------------------------------------------------------------------------+-- socketPortSafe+-- | Getting the port of socket.+socketPortSafe :: Socket                -- Connected & Bound Socket+               -> IO (Maybe PortNumber) -- Port Number of Socket+socketPortSafe s = do+    sa <- getSocketName s+    return $ case sa of+      SockAddrInet port _      -> Just port+      SockAddrInet6 port _ _ _ -> Just port+      _                        -> Nothing
+ Network/Socket/Options.hsc view
@@ -0,0 +1,242 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE ScopedTypeVariables #-}++#include "HsNet.h"+##include "HsNetDef.h"++module Network.Socket.Options (+    SocketOption(..)+  , isSupportedSocketOption+  , getSocketOption+  , setSocketOption+  , c_getsockopt+  , c_setsockopt+  ) where++import Foreign.Marshal.Alloc (alloca)+import Foreign.Marshal.Utils (with)++import Network.Socket.Imports+import Network.Socket.Internal+import Network.Socket.Types++-----------------------------------------------------------------------------+-- Socket Properties++-- | Socket options for use with 'setSocketOption' and 'getSocketOption'.+--+-- The existence of a constructor does not imply that the relevant option+-- is supported on your system: see 'isSupportedSocketOption'+data SocketOption+    = Debug         -- ^ SO_DEBUG+    | ReuseAddr     -- ^ SO_REUSEADDR+    | Type          -- ^ SO_TYPE+    | SoError       -- ^ SO_ERROR+    | DontRoute     -- ^ SO_DONTROUTE+    | Broadcast     -- ^ SO_BROADCAST+    | SendBuffer    -- ^ SO_SNDBUF+    | RecvBuffer    -- ^ SO_RCVBUF+    | KeepAlive     -- ^ SO_KEEPALIVE+    | OOBInline     -- ^ SO_OOBINLINE+    | TimeToLive    -- ^ IP_TTL+    | MaxSegment    -- ^ TCP_MAXSEG+    | NoDelay       -- ^ TCP_NODELAY+    | Cork          -- ^ TCP_CORK+    | Linger        -- ^ SO_LINGER: timeout in seconds, 0 means disabling/disabled.+    | ReusePort     -- ^ SO_REUSEPORT+    | RecvLowWater  -- ^ SO_RCVLOWAT+    | SendLowWater  -- ^ SO_SNDLOWAT+    | RecvTimeOut   -- ^ SO_RCVTIMEO: this does not work at this moment.+    | SendTimeOut   -- ^ SO_SNDTIMEO: this does not work at this moment.+    | UseLoopBack   -- ^ SO_USELOOPBACK+    | UserTimeout   -- ^ TCP_USER_TIMEOUT+    | IPv6Only      -- ^ IPV6_V6ONLY: don't use this on OpenBSD.+    | CustomSockOpt (CInt, CInt)+    deriving (Show, Typeable)++-- | Does the 'SocketOption' exist on this system?+isSupportedSocketOption :: SocketOption -> Bool+isSupportedSocketOption = isJust . packSocketOption++-- | For a socket option, return Just (level, value) where level is the+-- corresponding C option level constant (e.g. SOL_SOCKET) and value is+-- the option constant itself (e.g. SO_DEBUG)+-- If either constant does not exist, return Nothing.+packSocketOption :: SocketOption -> Maybe (CInt, CInt)+packSocketOption so =+  -- The Just here is a hack to disable GHC's overlapping pattern detection:+  -- the problem is if all constants are present, the fallback pattern is+  -- redundant, but if they aren't then it isn't. Hence we introduce an+  -- extra pattern (Nothing) that can't possibly happen, so that the+  -- fallback is always (in principle) necessary.+  -- I feel a little bad for including this, but such are the sacrifices we+  -- make while working with CPP - excluding the fallback pattern correctly+  -- would be a serious nuisance.+  -- (NB: comments elsewhere in this file refer to this one)+  case Just so of+#ifdef SOL_SOCKET+#ifdef SO_DEBUG+    Just Debug         -> Just ((#const SOL_SOCKET), (#const SO_DEBUG))+#endif+#ifdef SO_REUSEADDR+    Just ReuseAddr     -> Just ((#const SOL_SOCKET), (#const SO_REUSEADDR))+#endif+#ifdef SO_TYPE+    Just Type          -> Just ((#const SOL_SOCKET), (#const SO_TYPE))+#endif+#ifdef SO_ERROR+    Just SoError       -> Just ((#const SOL_SOCKET), (#const SO_ERROR))+#endif+#ifdef SO_DONTROUTE+    Just DontRoute     -> Just ((#const SOL_SOCKET), (#const SO_DONTROUTE))+#endif+#ifdef SO_BROADCAST+    Just Broadcast     -> Just ((#const SOL_SOCKET), (#const SO_BROADCAST))+#endif+#ifdef SO_SNDBUF+    Just SendBuffer    -> Just ((#const SOL_SOCKET), (#const SO_SNDBUF))+#endif+#ifdef SO_RCVBUF+    Just RecvBuffer    -> Just ((#const SOL_SOCKET), (#const SO_RCVBUF))+#endif+#ifdef SO_KEEPALIVE+    Just KeepAlive     -> Just ((#const SOL_SOCKET), (#const SO_KEEPALIVE))+#endif+#ifdef SO_OOBINLINE+    Just OOBInline     -> Just ((#const SOL_SOCKET), (#const SO_OOBINLINE))+#endif+#ifdef SO_LINGER+    Just Linger        -> Just ((#const SOL_SOCKET), (#const SO_LINGER))+#endif+#ifdef SO_REUSEPORT+    Just ReusePort     -> Just ((#const SOL_SOCKET), (#const SO_REUSEPORT))+#endif+#ifdef SO_RCVLOWAT+    Just RecvLowWater  -> Just ((#const SOL_SOCKET), (#const SO_RCVLOWAT))+#endif+#ifdef SO_SNDLOWAT+    Just SendLowWater  -> Just ((#const SOL_SOCKET), (#const SO_SNDLOWAT))+#endif+#ifdef SO_RCVTIMEO+    Just RecvTimeOut   -> Just ((#const SOL_SOCKET), (#const SO_RCVTIMEO))+#endif+#ifdef SO_SNDTIMEO+    Just SendTimeOut   -> Just ((#const SOL_SOCKET), (#const SO_SNDTIMEO))+#endif+#ifdef SO_USELOOPBACK+    Just UseLoopBack   -> Just ((#const SOL_SOCKET), (#const SO_USELOOPBACK))+#endif+#endif // SOL_SOCKET+#if HAVE_DECL_IPPROTO_IP+#ifdef IP_TTL+    Just TimeToLive    -> Just ((#const IPPROTO_IP), (#const IP_TTL))+#endif+#endif // HAVE_DECL_IPPROTO_IP+#if HAVE_DECL_IPPROTO_TCP+#ifdef TCP_MAXSEG+    Just MaxSegment    -> Just ((#const IPPROTO_TCP), (#const TCP_MAXSEG))+#endif+#ifdef TCP_NODELAY+    Just NoDelay       -> Just ((#const IPPROTO_TCP), (#const TCP_NODELAY))+#endif+#ifdef TCP_USER_TIMEOUT+    Just UserTimeout   -> Just ((#const IPPROTO_TCP), (#const TCP_USER_TIMEOUT))+#endif+#ifdef TCP_CORK+    Just Cork          -> Just ((#const IPPROTO_TCP), (#const TCP_CORK))+#endif+#endif // HAVE_DECL_IPPROTO_TCP+#if HAVE_DECL_IPPROTO_IPV6+#if HAVE_DECL_IPV6_V6ONLY+    Just IPv6Only      -> Just ((#const IPPROTO_IPV6), (#const IPV6_V6ONLY))+#endif+#endif // HAVE_DECL_IPPROTO_IPV6+    Just (CustomSockOpt opt) -> Just opt+    _             -> Nothing++-- | Return the option level and option value if they exist,+-- otherwise throw an error that begins "Network.Socket." ++ the String+-- parameter+packSocketOption' :: String -> SocketOption -> IO (CInt, CInt)+packSocketOption' caller so = maybe err return (packSocketOption so)+ where+  err = ioError . userError . concat $ ["Network.Socket.", caller,+    ": socket option ", show so, " unsupported on this system"]++#ifdef SO_LINGER+data StructLinger = StructLinger CInt CInt++instance Storable StructLinger where+    sizeOf _ = (#const sizeof(struct linger))+    alignment _ = alignment (undefined :: CInt)++    peek p = do+        onoff  <- (#peek struct linger, l_onoff) p+        linger <- (#peek struct linger, l_linger) p+        return $ StructLinger onoff linger++    poke p (StructLinger onoff linger) = do+        (#poke struct linger, l_onoff)  p onoff+        (#poke struct linger, l_linger) p linger+#endif++-- | Set a socket option that expects an Int value.+-- There is currently no API to set e.g. the timeval socket options+setSocketOption :: Socket+                -> SocketOption -- Option Name+                -> Int          -- Option Value+                -> IO ()+#ifdef SO_LINGER+setSocketOption s Linger v = do+   (level, opt) <- packSocketOption' "setSocketOption" Linger+   let arg = if v == 0 then StructLinger 0 0 else StructLinger 1 (fromIntegral v)+   with arg $ \ptr_arg -> void $ do+     let ptr = ptr_arg :: Ptr StructLinger+         sz = fromIntegral $ sizeOf (undefined :: StructLinger)+     fd <- fdSocket s+     throwSocketErrorIfMinus1_ "Network.Socket.setSocketOption" $+       c_setsockopt fd level opt ptr sz+#endif+setSocketOption s so v = do+   (level, opt) <- packSocketOption' "setSocketOption" so+   with (fromIntegral v) $ \ptr_v -> void $ do+     let ptr = ptr_v :: Ptr CInt+         sz  = fromIntegral $ sizeOf (undefined :: CInt)+     fd <- fdSocket s+     throwSocketErrorIfMinus1_ "Network.Socket.setSocketOption" $+       c_setsockopt fd level opt ptr sz++-- | Get a socket option that gives an Int value.+-- There is currently no API to get e.g. the timeval socket options+getSocketOption :: Socket+                -> SocketOption  -- Option Name+                -> IO Int        -- Option Value+#ifdef SO_LINGER+getSocketOption s Linger = do+   (level, opt) <- packSocketOption' "getSocketOption" Linger+   alloca $ \ptr_v -> do+     let ptr = ptr_v :: Ptr StructLinger+         sz = fromIntegral $ sizeOf (undefined :: StructLinger)+     fd <- fdSocket s+     with sz $ \ptr_sz -> do+       throwSocketErrorIfMinus1Retry_ "Network.Socket.getSocketOption" $+         c_getsockopt fd level opt ptr ptr_sz+       StructLinger onoff linger <- peek ptr+       return $ fromIntegral $ if onoff == 0 then 0 else linger+#endif+getSocketOption s so = do+   (level, opt) <- packSocketOption' "getSocketOption" so+   alloca $ \ptr_v -> do+     let ptr = ptr_v :: Ptr CInt+         sz = fromIntegral $ sizeOf (undefined :: CInt)+     fd <- fdSocket s+     with sz $ \ptr_sz -> do+       throwSocketErrorIfMinus1Retry_ "Network.Socket.getSocketOption" $+         c_getsockopt fd level opt ptr ptr_sz+       fromIntegral <$> peek ptr++foreign import CALLCONV unsafe "getsockopt"+  c_getsockopt :: CInt -> CInt -> CInt -> Ptr a -> Ptr CInt -> IO CInt+foreign import CALLCONV unsafe "setsockopt"+  c_setsockopt :: CInt -> CInt -> CInt -> Ptr a -> CInt -> IO CInt
+ Network/Socket/Shutdown.hs view
@@ -0,0 +1,37 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE DeriveDataTypeable #-}++#include "HsNetDef.h"++module Network.Socket.Shutdown (+    ShutdownCmd(..)+  , shutdown+  ) where++import Network.Socket.Imports+import Network.Socket.Internal+import Network.Socket.Types++data ShutdownCmd = ShutdownReceive+                 | ShutdownSend+                 | ShutdownBoth+                 deriving Typeable++sdownCmdToInt :: ShutdownCmd -> CInt+sdownCmdToInt ShutdownReceive = 0+sdownCmdToInt ShutdownSend    = 1+sdownCmdToInt ShutdownBoth    = 2++-- | Shut down one or both halves of the connection, depending on the+-- second argument to the function.  If the second argument is+-- 'ShutdownReceive', further receives are disallowed.  If it is+-- 'ShutdownSend', further sends are disallowed.  If it is+-- 'ShutdownBoth', further sends and receives are disallowed.+shutdown :: Socket -> ShutdownCmd -> IO ()+shutdown s stype = void $ do+  fd <- fdSocket s+  throwSocketErrorIfMinus1Retry_ "Network.Socket.shutdown" $+    c_shutdown fd $ sdownCmdToInt stype++foreign import CALLCONV unsafe "shutdown"+  c_shutdown :: CInt -> CInt -> IO CInt
+ Network/Socket/SockAddr.hs view
@@ -0,0 +1,66 @@+module Network.Socket.SockAddr (+      getPeerName+    , getSocketName+    , connect+    , bind+    , accept+    , sendBufTo+    , recvBufFrom+    ) where++import qualified Network.Socket.Buffer as G+import qualified Network.Socket.Name as G+import qualified Network.Socket.Syscall as G+import Network.Socket.Imports+import Network.Socket.Types++-- | Getting peer's 'SockAddr'.+getPeerName :: Socket -> IO SockAddr+getPeerName = G.getPeerName++-- | Getting my 'SockAddr'.+getSocketName :: Socket -> IO SockAddr+getSocketName = G.getSocketName++-- | Connect to a remote socket at address.+connect :: Socket -> SockAddr -> IO ()+connect = G.connect++-- | Bind the socket to an address. The socket must not already be+-- bound.  The 'Family' passed to @bind@ must be the+-- same as that passed to 'socket'.  If the special port number+-- 'defaultPort' is passed then the system assigns the next available+-- use port.+bind :: Socket -> SockAddr -> IO ()+bind = G.bind++-- | Accept a connection.  The socket must be bound to an address and+-- listening for connections.  The return value is a pair @(conn,+-- address)@ where @conn@ is a new socket object usable to send and+-- receive data on the connection, and @address@ is the address bound+-- to the socket on the other end of the connection.+-- On Unix, FD_CLOEXEC is set to the new 'Socket'.+accept :: Socket -> IO (Socket, SockAddr)+accept = G.accept++-- | Send data to the socket.  The recipient can be specified+-- 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.+sendBufTo :: Socket -> Ptr a -> Int -> SockAddr -> IO Int+sendBufTo = G.sendBufTo++-- | Receive data from the socket, writing it into buffer instead of+-- creating a new string.  The socket need not be in a connected+-- state. Returns @(nbytes, address)@ where @nbytes@ is the number of+-- bytes received and @address@ is a 'SockAddr' representing the+-- address of the sending socket.+--+-- If the first return value is zero, it means EOF.+--+-- For 'Stream' sockets, the second return value would be invalid.+--+-- NOTE: blocking on Windows unless you compile with -threaded (see+-- GHC ticket #1129)+recvBufFrom :: Socket -> Ptr a -> Int -> IO (Int, SockAddr)+recvBufFrom = G.recvBufFrom
+ Network/Socket/Syscall.hs view
@@ -0,0 +1,257 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE ScopedTypeVariables #-}++#include "HsNetDef.h"++module Network.Socket.Syscall where++import Foreign.Marshal.Utils (with)+import qualified Control.Exception as E++#if defined(mingw32_HOST_OS)+import Foreign (FunPtr)+import GHC.Conc (asyncDoProc)+#else+import Foreign.C.Error (getErrno, eINTR, eINPROGRESS)+import GHC.Conc (threadWaitWrite)+#endif++#ifdef HAVE_ADVANCED_SOCKET_FLAGS+import Network.Socket.Cbits+#else+import Network.Socket.Fcntl+#endif++import Network.Socket.Imports+import Network.Socket.Internal+import Network.Socket.Options+import Network.Socket.Types++-- ----------------------------------------------------------------------------+-- On Windows, our sockets are not put in non-blocking mode (non-blocking+-- is not supported for regular file descriptors on Windows, and it would+-- be a pain to support it only for sockets).  So there are two cases:+--+--  - the threaded RTS uses safe calls for socket operations to get+--    non-blocking I/O, just like the rest of the I/O library+--+--  - with the non-threaded RTS, only some operations on sockets will be+--    non-blocking.  Reads and writes go through the normal async I/O+--    system.  accept() uses asyncDoProc so is non-blocking.  A handful+--    of others (recvFrom, sendFd, recvFd) will block all threads - if this+--    is a problem, -threaded is the workaround.+--++-----------------------------------------------------------------------------+-- Connection Functions++-- In the following connection and binding primitives.  The names of+-- the equivalent C functions have been preserved where possible. It+-- should be noted that some of these names used in the C library,+-- \tr{bind} in particular, have a different meaning to many Haskell+-- programmers and have thus been renamed by appending the prefix+-- Socket.++-- | Create a new socket using the given address family, socket type+-- 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 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.+--+-- >>> import Network.Socket+-- >>> let hints = defaultHints { addrFlags = [AI_NUMERICHOST, AI_NUMERICSERV], addrSocketType = Stream }+-- >>> addr:_ <- getAddrInfo (Just hints) (Just "127.0.0.1") (Just "5000")+-- >>> sock <- socket (addrFamily addr) (addrSocketType addr) (addrProtocol addr)+-- >>> Network.Socket.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)+       -> IO Socket      -- Unconnected Socket+socket family stype protocol = E.bracketOnError create c_close $ \fd -> do+    -- Let's ensure that the socket (file descriptor) is closed even on+    -- asynchronous exceptions.+    setNonBlock fd+    s <- mkSocket fd+    -- This socket is not managed by the IO manager yet.+    -- So, we don't have to call "close" which uses "closeFdWith".+    unsetIPv6Only s+    return s+  where+    create = do+        c_stype <- modifyFlag <$> packSocketTypeOrThrow "socket" stype+        throwSocketErrorIfMinus1Retry "Network.Socket.socket" $+            c_socket (packFamily family) c_stype protocol++#ifdef HAVE_ADVANCED_SOCKET_FLAGS+    modifyFlag c_stype = c_stype .|. sockNonBlock+#else+    modifyFlag c_stype = c_stype+#endif++#ifdef HAVE_ADVANCED_SOCKET_FLAGS+    setNonBlock _ = return ()+#else+    setNonBlock fd = setNonBlockIfNeeded fd+#endif++#if HAVE_DECL_IPV6_V6ONLY+    unsetIPv6Only s = when (family == AF_INET6 && stype `elem` [Stream, Datagram]) $+# 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.+      E.catch (setSocketOption s IPv6Only 0) $ (\(_ :: E.IOException) -> return ())+# elif defined(__OpenBSD__)+      -- don't change IPv6Only+      return ()+# else+      -- The default value of the IPv6Only option is platform specific,+      -- so we explicitly set it to 0 to provide a common default.+      setSocketOption s IPv6Only 0+# endif+#else+    unsetIPv6Only _ = return ()+#endif++-----------------------------------------------------------------------------+-- Binding a socket++-- | Bind the socket to an address. The socket must not already be+-- bound.  The 'Family' passed to @bind@ must be the+-- same as that passed to 'socket'.  If the special port number+-- 'defaultPort' is passed then the system assigns the next available+-- use port.+bind :: SocketAddress sa => Socket -> sa -> IO ()+bind s sa = withSocketAddress sa $ \p_sa siz -> void $ do+  fd <- fdSocket s+  let sz = fromIntegral siz+  throwSocketErrorIfMinus1Retry "Network.Socket.bind" $ c_bind fd p_sa sz++-----------------------------------------------------------------------------+-- Connecting a socket++-- | Connect to a remote socket at address.+connect :: SocketAddress sa => Socket -> sa -> IO ()+connect s sa = withSocketsDo $ withSocketAddress sa $ \p_sa sz ->+    connectLoop s p_sa (fromIntegral sz)++connectLoop :: SocketAddress sa => Socket -> Ptr sa -> CInt -> IO ()+connectLoop s p_sa sz = loop+  where+    errLoc = "Network.Socket.connect: " ++ show s+    loop = do+       fd <- fdSocket s+       r <- c_connect fd p_sa sz+       when (r == -1) $ do+#if defined(mingw32_HOST_OS)+           throwSocketError errLoc+#else+           err <- getErrno+           case () of+             _ | err == eINTR       -> loop+             _ | err == eINPROGRESS -> connectBlocked+--           _ | err == eAGAIN      -> connectBlocked+             _otherwise             -> throwSocketError errLoc++    connectBlocked = do+       fd <- fromIntegral <$> fdSocket s+       threadWaitWrite fd+       err <- getSocketOption s SoError+       when (err == -1) $ throwSocketErrorCode errLoc (fromIntegral err)+#endif++-----------------------------------------------------------------------------+-- Listen++-- | Listen for connections made to the socket.  The second argument+-- specifies the maximum number of queued connections and should be at+-- least 1; the maximum value is system-dependent (usually 5).+listen :: Socket -> Int -> IO ()+listen s backlog = do+    fd <- fdSocket s+    throwSocketErrorIfMinus1Retry_ "Network.Socket.listen" $+        c_listen fd $ fromIntegral backlog++-----------------------------------------------------------------------------+-- Accept+--+-- A call to `accept' only returns when data is available on the given+-- socket, unless the socket has been set to non-blocking.  It will+-- return a new socket which should be used to read the incoming data and+-- should then be closed. Using the socket returned by `accept' allows+-- incoming requests to be queued on the original socket.++-- | Accept a connection.  The socket must be bound to an address and+-- listening for connections.  The return value is a pair @(conn,+-- address)@ where @conn@ is a new socket object usable to send and+-- receive data on the connection, and @address@ is the address bound+-- to the socket on the other end of the connection.+-- On Unix, FD_CLOEXEC is set to the new 'Socket'.+accept :: SocketAddress sa => Socket -> IO (Socket, sa)+accept listing_sock = withNewSocketAddress $ \new_sa sz -> do+     listing_fd <- fdSocket listing_sock+     new_sock <- callAccept listing_fd new_sa sz >>= mkSocket+     new_addr <- peekSocketAddress new_sa+     return (new_sock, new_addr)+  where+#if defined(mingw32_HOST_OS)+     callAccept fd sa sz+       | threaded  = with (fromIntegral sz) $ \ ptr_len ->+                       throwSocketErrorIfMinus1Retry "Network.Socket.accept" $+                         c_accept_safe fd sa ptr_len+       | otherwise = do+             paramData <- c_newAcceptParams fd (fromIntegral sz) sa+             rc        <- asyncDoProc c_acceptDoProc paramData+             new_fd    <- c_acceptNewSock paramData+             c_free paramData+             when (rc /= 0) $+               throwSocketErrorCode "Network.Socket.accept" (fromIntegral rc)+             return new_fd+#else+     callAccept fd sa sz = with (fromIntegral sz) $ \ ptr_len -> do+# ifdef HAVE_ADVANCED_SOCKET_FLAGS+       throwSocketErrorWaitRead listing_sock "Network.Socket.accept"+                        (c_accept4 fd sa ptr_len (sockNonBlock .|. sockCloexec))+# else+       new_fd <- throwSocketErrorWaitRead listing_sock "Network.Socket.accept"+                        (c_accept fd sa ptr_len)+       setNonBlockIfNeeded new_fd+       setCloseOnExecIfNeeded new_fd+       return new_fd+# endif /* HAVE_ADVANCED_SOCKET_FLAGS */+#endif++foreign import CALLCONV unsafe "socket"+  c_socket :: CInt -> CInt -> CInt -> IO CInt+foreign import CALLCONV unsafe "bind"+  c_bind :: CInt -> Ptr sa -> CInt{-CSockLen???-} -> IO CInt+foreign import CALLCONV SAFE_ON_WIN "connect"+  c_connect :: CInt -> Ptr sa -> CInt{-CSockLen???-} -> IO CInt+foreign import CALLCONV unsafe "listen"+  c_listen :: CInt -> CInt -> IO CInt++#ifdef HAVE_ADVANCED_SOCKET_FLAGS+foreign import CALLCONV unsafe "accept4"+  c_accept4 :: CInt -> Ptr sa -> Ptr CInt{-CSockLen???-} -> CInt -> IO CInt+#else+foreign import CALLCONV unsafe "accept"+  c_accept :: CInt -> Ptr sa -> Ptr CInt{-CSockLen???-} -> IO CInt+#endif++#if defined(mingw32_HOST_OS)+foreign import CALLCONV safe "accept"+  c_accept_safe :: CInt -> Ptr sa -> Ptr CInt{-CSockLen???-} -> IO CInt+foreign import ccall unsafe "rtsSupportsBoundThreads"+  threaded :: Bool+foreign import ccall unsafe "HsNet.h acceptNewSock"+  c_acceptNewSock :: Ptr () -> IO CInt+foreign import ccall unsafe "HsNet.h newAcceptParams"+  c_newAcceptParams :: CInt -> CInt -> Ptr a -> IO (Ptr ())+foreign import ccall unsafe "HsNet.h &acceptDoProc"+  c_acceptDoProc :: FunPtr (Ptr () -> IO Int)+foreign import ccall unsafe "free"+  c_free:: Ptr a -> IO ()+#endif
Network/Socket/Types.hsc view
@@ -1,23 +1,22 @@+{-# LANGUAGE CPP #-} {-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE ForeignFunctionInterface #-}+{-# LANGUAGE RecordWildCards #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-}  #include "HsNet.h" ##include "HsNetDef.h" -module Network.Socket.Types-    (-    -- * Socket-      Socket(..)+module Network.Socket.Types (+    -- * Socket type+      Socket     , fdSocket-    , sockFamily-    , sockType-    , sockProtocol-    , sockStatus-    , SocketStatus(..)--    -- * Socket types+    , mkSocket+    , invalidateSocket+    , close+    , close'+    , c_close+    -- * Types of socket     , SocketType(..)     , isSupportedSocketType     , packSocketType@@ -32,61 +31,64 @@     , packFamily     , unpackFamily -    -- * Socket addresses+    -- * Socket address typeclass+    , SocketAddress(..)+    , withSocketAddress+    , withNewSocketAddress++    -- * Socket address type     , SockAddr(..)     , isSupportedSockAddr     , HostAddress     , hostAddressToTuple     , tupleToHostAddress-#if defined(IPV6_SOCKET_SUPPORT)     , HostAddress6     , hostAddress6ToTuple     , tupleToHostAddress6     , FlowInfo     , ScopeID-#endif     , peekSockAddr     , pokeSockAddr-    , sizeOfSockAddr-    , sizeOfSockAddrByFamily     , withSockAddr-    , withNewSockAddr      -- * Unsorted     , ProtocolNumber-    , PortNumber(..)+    , defaultProtocol+    , PortNumber+    , defaultPort      -- * Low-level helpers     , zeroMemory+    , htonl+    , ntohl     ) where -import Control.Concurrent.MVar-import Control.Monad-import Data.Bits-import Data.Maybe-import Data.Typeable-import Data.Word-import Data.Int-import Foreign.C+import Control.Monad (when)+import Data.IORef (IORef, newIORef, readIORef, atomicModifyIORef', mkWeakIORef)+import Foreign.C.Error (throwErrno) import Foreign.Marshal.Alloc+import GHC.Conc (closeFdWith)+import System.Posix.Types (Fd)+import Control.DeepSeq (NFData (..))++#if defined(DOMAIN_SOCKET_SUPPORT) import Foreign.Marshal.Array-import Foreign.Ptr-import Foreign.Storable+#endif --- | A socket data type.---  'Socket's are not GCed unless they are closed by 'close'.-data Socket-  = MkSocket-            CInt                 -- File Descriptor-            Family-            SocketType-            ProtocolNumber       -- Protocol Number-            (MVar SocketStatus)  -- Status Flag-  deriving Typeable+import Network.Socket.Imports -{-# DEPRECATED MkSocket "'MkSocket' will not be available in version 3.0.0.0 or later. Use fdSocket instead" #-}+----------------------------------------------------------------------------- --- | Obtaining the file descriptor from a socket.+-- | Basic type for a socket.+data Socket = Socket !(IORef CInt) !CInt {- for Show -}++instance Show Socket where+    show (Socket _ ofd) = "<socket: " ++ show ofd ++ ">"++instance Eq Socket where+    Socket ref1 _ == Socket ref2 _ = ref1 == ref2++-- | Getting a file descriptor from a socket. -- --   If a 'Socket' is shared with multiple threads and --   one uses 'fdSocket', unexpected issues may happen.@@ -102,46 +104,92 @@ --   In this case, it is safer for Thread A to clone 'Fd' by --   'System.Posix.IO.dup'. But this would still suffer from --   a rase condition between 'fdSocket' and 'close'.-fdSocket :: Socket -> CInt-fdSocket (MkSocket fd _ _ _ _) = fd+fdSocket :: Socket -> IO CInt+fdSocket (Socket ref _) = readIORef ref -sockFamily :: Socket -> Family-sockFamily   (MkSocket _ f _ _ _) = f+-- | Creating a socket from a file descriptor.+mkSocket :: CInt -> IO Socket+mkSocket fd = do+    ref <- newIORef fd+    let s = Socket ref fd+    void $ mkWeakIORef ref $ close s+    return s -sockType :: Socket -> SocketType-sockType     (MkSocket _ _ t _ _) = t+invalidSocket :: CInt+#if defined(mingw32_HOST_OS)+invalidSocket = #const INVALID_SOCKET+#else+invalidSocket = -1+#endif -sockProtocol :: Socket -> ProtocolNumber-sockProtocol (MkSocket _ _ _ p _) = p+invalidateSocket ::+      Socket+   -> (CInt -> IO a)+   -> (CInt -> IO a)+   -> IO a+invalidateSocket (Socket ref _) errorAction normalAction = do+    oldfd <- atomicModifyIORef' ref $ \cur -> (invalidSocket, cur)+    if oldfd == invalidSocket then errorAction oldfd else normalAction oldfd -sockStatus :: Socket -> MVar SocketStatus-sockStatus   (MkSocket _ _ _ _ s) = s+----------------------------------------------------------------------------- -instance Eq Socket where-  (MkSocket _ _ _ _ m1) == (MkSocket _ _ _ _ m2) = m1 == m2+-- | Close the socket. This function does not throw exceptions even if+--   the underlying system call returns errors.+--+--   Sending data to or receiving data from closed socket+--   may lead to undefined behaviour.+--+--   If multiple threads use the same socket and one uses 'fdSocket' and+--   the other use 'close', unexpected behavior may happen.+--   For more information, please refer to the documentation of 'fdSocket'.+close :: Socket -> IO ()+close s = invalidateSocket s (\_ -> return ()) $ \oldfd -> do+    -- closeFdWith avoids the deadlock of IO manager.+    closeFdWith closeFd (toFd oldfd)+  where+    toFd :: CInt -> Fd+    toFd = fromIntegral+    -- closeFd ignores the return value of c_close and+    -- does not throw exceptions+    closeFd :: Fd -> IO ()+    closeFd = void . c_close . fromIntegral -instance Show Socket where-  showsPrec _n (MkSocket fd _ _ _ _) =-        showString "<socket: " . shows fd . showString ">"+-- | Close the socket. This function throws exceptions if+--   the underlying system call returns errors.+--+--   Sending data to or receiving data from closed socket+--   may lead to undefined behaviour.+close' :: Socket -> IO ()+close' s = invalidateSocket s (\_ -> return ()) $ \oldfd -> do+    -- closeFdWith avoids the deadlock of IO manager.+    closeFdWith closeFd (toFd oldfd)+  where+    toFd :: CInt -> Fd+    toFd = fromIntegral+    closeFd :: Fd -> IO ()+    closeFd fd = do+        ret <- c_close $ fromIntegral fd+        when (ret == -1) $ throwErrno "Network.Socket.close'" +#if defined(mingw32_HOST_OS)+foreign import CALLCONV unsafe "closesocket"+  c_close :: CInt -> IO CInt+#else+foreign import ccall unsafe "close"+  c_close :: CInt -> IO CInt+#endif++-----------------------------------------------------------------------------++-- | Protocl number. type ProtocolNumber = CInt --- | The status of the socket as /determined by this library/, not--- necessarily reflecting the state of the connection itself.+-- | This is the default protocol for a given service. ----- For example, the 'Closed' status is applied when the 'close'--- function is called.-data SocketStatus-  -- Returned Status    Function called-  = NotConnected        -- ^ Newly created, unconnected socket-  | Bound               -- ^ Bound, via 'bind'-  | Listening           -- ^ Listening, via 'listen'-  | Connected           -- ^ Connected or accepted, via 'connect' or 'accept'-  | ConvertedToHandle   -- ^ Is now a 'Handle' (via 'socketToHandle'), don't touch-  | Closed              -- ^ Closed was closed by 'close'-    deriving (Eq, Show, Typeable)--{-# DEPRECATED SocketStatus "SocketStatus will be removed" #-}+-- >>> defaultProtocol+-- 0+defaultProtocol :: ProtocolNumber+defaultProtocol = 0  ----------------------------------------------------------------------------- -- Socket types@@ -201,8 +249,6 @@ #endif     _ -> Nothing -{-# DEPRECATED packSocketType "packSocketType will not be available in version 3.0.0.0 or later." #-}- packSocketType :: SocketType -> CInt packSocketType stype = fromMaybe (error errMsg) (packSocketType' stype)   where@@ -254,74 +300,75 @@ -- A constructor being present here does not mean it is supported by the -- operating system: see 'isSupportedFamily'. data Family-    = AF_UNSPEC           -- unspecified-    | AF_UNIX             -- local to host (pipes, portals-    | AF_INET             -- internetwork: UDP, TCP, etc-    | AF_INET6            -- Internet Protocol version 6-    | AF_IMPLINK          -- arpanet imp addresses-    | AF_PUP              -- pup protocols: e.g. BSP-    | AF_CHAOS            -- mit CHAOS protocols-    | AF_NS               -- XEROX NS protocols-    | AF_NBS              -- nbs protocols-    | AF_ECMA             -- european computer manufacturers-    | AF_DATAKIT          -- datakit protocols-    | AF_CCITT            -- CCITT protocols, X.25 etc-    | AF_SNA              -- IBM SNA-    | AF_DECnet           -- DECnet-    | AF_DLI              -- Direct data link interface-    | AF_LAT              -- LAT-    | AF_HYLINK           -- NSC Hyperchannel-    | AF_APPLETALK        -- Apple Talk-    | AF_ROUTE            -- Internal Routing Protocol (aka AF_NETLINK)-    | AF_NETBIOS          -- NetBios-style addresses-    | AF_NIT              -- Network Interface Tap-    | AF_802              -- IEEE 802.2, also ISO 8802-    | AF_ISO              -- ISO protocols-    | AF_OSI              -- umbrella of all families used by OSI-    | AF_NETMAN           -- DNA Network Management-    | AF_X25              -- CCITT X.25-    | AF_AX25-    | AF_OSINET           -- AFI-    | AF_GOSSIP           -- US Government OSI-    | AF_IPX              -- Novell Internet Protocol-    | Pseudo_AF_XTP       -- eXpress Transfer Protocol (no AF)-    | AF_CTF              -- Common Trace Facility-    | AF_WAN              -- Wide Area Network protocols-    | AF_SDL              -- SGI Data Link for DLPI-    | AF_NETWARE-    | AF_NDD-    | AF_INTF             -- Debugging use only-    | AF_COIP             -- connection-oriented IP, aka ST II-    | AF_CNT              -- Computer Network Technology-    | Pseudo_AF_RTIP      -- Help Identify RTIP packets-    | Pseudo_AF_PIP       -- Help Identify PIP packets-    | AF_SIP              -- Simple Internet Protocol-    | AF_ISDN             -- Integrated Services Digital Network-    | Pseudo_AF_KEY       -- Internal key-management function-    | AF_NATM             -- native ATM access-    | AF_ARP              -- (rev.) addr. res. prot. (RFC 826)-    | Pseudo_AF_HDRCMPLT  -- Used by BPF to not rewrite hdrs in iface output-    | AF_ENCAP-    | AF_LINK             -- Link layer interface-    | AF_RAW              -- Link layer interface-    | AF_RIF              -- raw interface-    | AF_NETROM           -- Amateur radio NetROM-    | AF_BRIDGE           -- multiprotocol bridge-    | AF_ATMPVC           -- ATM PVCs-    | AF_ROSE             -- Amateur Radio X.25 PLP-    | AF_NETBEUI          -- 802.2LLC-    | AF_SECURITY         -- Security callback pseudo AF-    | AF_PACKET           -- Packet family-    | AF_ASH              -- Ash-    | AF_ECONET           -- Acorn Econet-    | AF_ATMSVC           -- ATM SVCs-    | AF_IRDA             -- IRDA sockets-    | AF_PPPOX            -- PPPoX sockets-    | AF_WANPIPE          -- Wanpipe API sockets-    | AF_BLUETOOTH        -- bluetooth sockets-    | AF_CAN              -- Controller Area Network+    = AF_UNSPEC           -- ^ unspecified+    | AF_UNIX             -- ^ UNIX-domain+    | AF_INET             -- ^ Internet Protocol version 4+    | AF_INET6            -- ^ Internet Protocol version 6+    | AF_IMPLINK          -- ^ Arpanet imp addresses+    | AF_PUP              -- ^ pup protocols: e.g. BSP+    | AF_CHAOS            -- ^ mit CHAOS protocols+    | AF_NS               -- ^ XEROX NS protocols+    | AF_NBS              -- ^ nbs protocols+    | AF_ECMA             -- ^ european computer manufacturers+    | AF_DATAKIT          -- ^ datakit protocols+    | AF_CCITT            -- ^ CCITT protocols, X.25 etc+    | AF_SNA              -- ^ IBM SNA+    | AF_DECnet           -- ^ DECnet+    | AF_DLI              -- ^ Direct data link interface+    | AF_LAT              -- ^ LAT+    | AF_HYLINK           -- ^ NSC Hyperchannel+    | AF_APPLETALK        -- ^ Apple Talk+    | AF_ROUTE            -- ^ Internal Routing Protocol (aka AF_NETLINK)+    | AF_NETBIOS          -- ^ NetBios-style addresses+    | AF_NIT              -- ^ Network Interface Tap+    | AF_802              -- ^ IEEE 802.2, also ISO 8802+    | AF_ISO              -- ^ ISO protocols+    | AF_OSI              -- ^ umbrella of all families used by OSI+    | AF_NETMAN           -- ^ DNA Network Management+    | AF_X25              -- ^ CCITT X.25+    | AF_AX25             -- ^ AX25+    | AF_OSINET           -- ^ AFI+    | AF_GOSSIP           -- ^ US Government OSI+    | AF_IPX              -- ^ Novell Internet Protocol+    | Pseudo_AF_XTP       -- ^ eXpress Transfer Protocol (no AF)+    | AF_CTF              -- ^ Common Trace Facility+    | AF_WAN              -- ^ Wide Area Network protocols+    | AF_SDL              -- ^ SGI Data Link for DLPI+    | AF_NETWARE          -- ^ Netware+    | AF_NDD              -- ^ NDD+    | AF_INTF             -- ^ Debugging use only+    | AF_COIP             -- ^ connection-oriented IP, aka ST II+    | AF_CNT              -- ^ Computer Network Technology+    | Pseudo_AF_RTIP      -- ^ Help Identify RTIP packets+    | Pseudo_AF_PIP       -- ^ Help Identify PIP packets+    | AF_SIP              -- ^ Simple Internet Protocol+    | AF_ISDN             -- ^ Integrated Services Digital Network+    | Pseudo_AF_KEY       -- ^ Internal key-management function+    | AF_NATM             -- ^ native ATM access+    | AF_ARP              -- ^ ARP (RFC 826)+    | Pseudo_AF_HDRCMPLT  -- ^ Used by BPF to not rewrite hdrs in iface output+    | AF_ENCAP            -- ^ ENCAP+    | AF_LINK             -- ^ Link layer interface+    | AF_RAW              -- ^ Link layer interface+    | AF_RIF              -- ^ raw interface+    | AF_NETROM           -- ^ Amateur radio NetROM+    | AF_BRIDGE           -- ^ multiprotocol bridge+    | AF_ATMPVC           -- ^ ATM PVCs+    | AF_ROSE             -- ^ Amateur Radio X.25 PLP+    | AF_NETBEUI          -- ^ Netbeui 802.2LLC+    | AF_SECURITY         -- ^ Security callback pseudo AF+    | AF_PACKET           -- ^ Packet family+    | AF_ASH              -- ^ Ash+    | AF_ECONET           -- ^ Acorn Econet+    | AF_ATMSVC           -- ^ ATM SVCs+    | AF_IRDA             -- ^ IRDA sockets+    | AF_PPPOX            -- ^ PPPoX sockets+    | AF_WANPIPE          -- ^ Wanpipe API sockets+    | AF_BLUETOOTH        -- ^ bluetooth sockets+    | AF_CAN              -- ^ Controller Area Network       deriving (Eq, Ord, Read, Show) +-- | Converting 'Family' to 'CInt'. packFamily :: Family -> CInt packFamily f = case packFamily' f of     Just fam -> fam@@ -538,6 +585,7 @@  --------- ---------- +-- | Converting 'CInt' to 'Family'. unpackFamily :: CInt -> Family unpackFamily f = case f of         (#const AF_UNSPEC) -> AF_UNSPEC@@ -745,8 +793,9 @@ ------------------------------------------------------------------------ -- Port Numbers --- | Use the @Num@ instance (i.e. use a literal) to create a--- @PortNumber@ value.+-- | Port number.+--   Use the @Num@ instance (i.e. use a literal) to create a+--   @PortNumber@ value. -- -- >>> 1 :: PortNumber -- 1@@ -772,16 +821,50 @@  foreign import CALLCONV unsafe "ntohs" ntohs :: Word16 -> Word16 foreign import CALLCONV unsafe "htons" htons :: Word16 -> Word16-foreign import CALLCONV unsafe "ntohl" ntohl :: Word32 -> Word32+-- | 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+{-# DEPRECATED htonl "Use getAddrInfo instead" #-}+{-# DEPRECATED ntohl "Use getAddrInfo instead" #-}  instance Storable PortNumber where    sizeOf    _ = sizeOf    (undefined :: Word16)    alignment _ = alignment (undefined :: Word16)    poke p (PortNum po) = poke (castPtr p) (htons po)-   peek p = (PortNum . ntohs) `liftM` peek (castPtr p)+   peek p = PortNum . ntohs <$> peek (castPtr p) +-- | Default port number.+--+-- >>> defaultPort+-- 0+defaultPort :: PortNumber+defaultPort = 0+ ------------------------------------------------------------------------++-- | The core typeclass to unify socket addresses.+class SocketAddress sa where+    sizeOfSocketAddress :: sa -> Int+    peekSocketAddress :: Ptr sa -> IO sa+    pokeSocketAddress  :: Ptr a -> sa -> IO ()++-- sizeof(struct sockaddr_storage) which has enough space to contain+-- sockaddr_in, sockaddr_in6 and sockaddr_un.+sockaddrStorageLen :: Int+sockaddrStorageLen = 128++withSocketAddress :: SocketAddress sa => sa -> (Ptr sa -> Int -> IO a) -> IO a+withSocketAddress addr f = do+    let sz = sizeOfSocketAddress addr+    allocaBytes sz $ \p -> pokeSocketAddress p addr >> f (castPtr p) sz++withNewSocketAddress :: SocketAddress sa => (Ptr sa -> Int -> IO a) -> IO a+withNewSocketAddress f = allocaBytes sockaddrStorageLen $ \ptr -> do+    zeroMemory ptr $ fromIntegral sockaddrStorageLen+    f ptr sockaddrStorageLen++------------------------------------------------------------------------ -- Socket addresses  -- The scheme used for addressing sockets is somewhat quirky. The@@ -801,49 +884,51 @@ -- families. Currently only UNIX-domain sockets and the Internet -- families are supported. +-- | Flow information. type FlowInfo = Word32+-- | Scope identifier. type ScopeID = Word32 --- | The existence of a constructor does not necessarily imply that--- that socket address type is supported on your system: see+-- | Socket addresses.+--  The existence of a constructor does not necessarily imply that+--  that socket address type is supported on your system: see -- 'isSupportedSockAddr'.-data SockAddr       -- C Names+data SockAddr   = SockAddrInet-    PortNumber  -- sin_port-    HostAddress -- sin_addr  (ditto)+        !PortNumber      -- sin_port+        !HostAddress     -- sin_addr  (ditto)   | SockAddrInet6-        PortNumber      -- sin6_port-        FlowInfo        -- sin6_flowinfo (ditto)-        HostAddress6    -- sin6_addr (ditto)-        ScopeID         -- sin6_scope_id (ditto)+        !PortNumber      -- sin6_port+        !FlowInfo        -- sin6_flowinfo (ditto)+        !HostAddress6    -- sin6_addr (ditto)+        !ScopeID         -- sin6_scope_id (ditto)+  -- | 'String' must be a list of 0-255 values and its length should be less than 104.   | SockAddrUnix-        String          -- sun_path-  | SockAddrCan-        Int32           -- can_ifindex (can be get by Network.BSD.ifNameToIndex "can0")-        -- TODO: Extend this to include transport protocol information+        String           -- sun_path   deriving (Eq, Ord, Typeable) +instance NFData SockAddr where+  rnf (SockAddrInet _ _) = ()+  rnf (SockAddrInet6 _ _ _ _) = ()+  rnf (SockAddrUnix str) = rnf str+ -- | Is the socket address type supported on this system? isSupportedSockAddr :: SockAddr -> Bool isSupportedSockAddr addr = case addr of-  SockAddrInet {} -> True-#if defined(IPV6_SOCKET_SUPPORT)-  SockAddrInet6 {} -> True-#endif+  SockAddrInet{}  -> True+  SockAddrInet6{} -> True #if defined(DOMAIN_SOCKET_SUPPORT)-  SockAddrUnix{} -> True-#endif-#if defined(CAN_SOCKET_SUPPORT)-  SockAddrCan{} -> True-#endif-#if !(defined(IPV6_SOCKET_SUPPORT) \-      && defined(DOMAIN_SOCKET_SUPPORT) && defined(CAN_SOCKET_SUPPORT))-  _ -> False+  SockAddrUnix{}  -> True+#else+  SockAddrUnix{}  -> False #endif -{-# DEPRECATED SockAddrCan "This will be removed in 3.0" #-}+instance SocketAddress SockAddr where+    sizeOfSocketAddress = sizeOfSockAddr+    peekSocketAddress   = peekSockAddr+    pokeSocketAddress   = pokeSockAddr -#if defined(WITH_WINSOCK)+#if defined(mingw32_HOST_OS) type CSaFamily = (#type unsigned short) #elif defined(darwin_HOST_OS) type CSaFamily = (#type u_char)@@ -856,39 +941,12 @@ -- in that the value of the argument /is/ used. sizeOfSockAddr :: SockAddr -> Int #if defined(DOMAIN_SOCKET_SUPPORT)-sizeOfSockAddr (SockAddrUnix path) =-    case path of-        '\0':_ -> (#const sizeof(sa_family_t)) + length path-        _      -> #const sizeof(struct sockaddr_un)-#endif-sizeOfSockAddr (SockAddrInet _ _) = #const sizeof(struct sockaddr_in)-#if defined(IPV6_SOCKET_SUPPORT)-sizeOfSockAddr (SockAddrInet6 _ _ _ _) = #const sizeof(struct sockaddr_in6)-#endif-#if defined(CAN_SOCKET_SUPPORT)-sizeOfSockAddr (SockAddrCan _) = #const sizeof(struct sockaddr_can)-#endif-#if !(defined(IPV6_SOCKET_SUPPORT) \-      && defined(DOMAIN_SOCKET_SUPPORT) && defined(CAN_SOCKET_SUPPORT))-sizeOfSockAddr _ = error "sizeOfSockAddr: not supported"-#endif---- | Computes the storage requirements (in bytes) required for a--- 'SockAddr' with the given 'Family'.-sizeOfSockAddrByFamily :: Family -> Int-#if defined(DOMAIN_SOCKET_SUPPORT)-sizeOfSockAddrByFamily AF_UNIX  = #const sizeof(struct sockaddr_un)-#endif-#if defined(IPV6_SOCKET_SUPPORT)-sizeOfSockAddrByFamily AF_INET6 = #const sizeof(struct sockaddr_in6)-#endif-sizeOfSockAddrByFamily AF_INET  = #const sizeof(struct sockaddr_in)-#if defined(CAN_SOCKET_SUPPORT)-sizeOfSockAddrByFamily AF_CAN   = #const sizeof(struct sockaddr_can)+sizeOfSockAddr SockAddrUnix{}  = #const sizeof(struct sockaddr_un)+#else+sizeOfSockAddr SockAddrUnix{}  = error "sizeOfSockAddr: not supported" #endif-sizeOfSockAddrByFamily family = error $-    "Network.Socket.Types.sizeOfSockAddrByFamily: address family '" ++-    show family ++ "' not supported."+sizeOfSockAddr SockAddrInet{}  = #const sizeof(struct sockaddr_in)+sizeOfSockAddr SockAddrInet6{} = #const sizeof(struct sockaddr_in6)  -- | Use a 'SockAddr' with a function requiring a pointer to a -- 'SockAddr' and the length of that 'SockAddr'.@@ -897,13 +955,6 @@     let sz = sizeOfSockAddr addr     allocaBytes sz $ \p -> pokeSockAddr p addr >> f (castPtr p) sz --- | Create a new 'SockAddr' for use with a function requiring a--- pointer to a 'SockAddr' and the length of that 'SockAddr'.-withNewSockAddr :: Family -> (Ptr SockAddr -> Int -> IO a) -> IO a-withNewSockAddr family f = do-    let sz = sizeOfSockAddrByFamily family-    allocaBytes sz $ \ptr -> f ptr sz- -- We cannot bind sun_paths longer than than the space in the sockaddr_un -- structure, and attempting to do so could overflow the allocated storage -- space.  This constant holds the maximum allowable path length.@@ -926,48 +977,34 @@ pokeSockAddr p sa@(SockAddrUnix path) = do     when (length path > unixPathMax) $ error "pokeSockAddr: path is too long"     zeroMemory p $ fromIntegral $ sizeOfSockAddr sa-#if defined(HAVE_STRUCT_SOCKADDR_SA_LEN)+# if defined(HAVE_STRUCT_SOCKADDR_SA_LEN)     (#poke struct sockaddr_un, sun_len) p ((#const sizeof(struct sockaddr_un)) :: Word8)-#endif+# endif     (#poke struct sockaddr_un, sun_family) p ((#const AF_UNIX) :: CSaFamily)     let pathC = map castCharToCChar path+    -- the buffer is already filled with nulls.     pokeArray ((#ptr struct sockaddr_un, sun_path) p) pathC+#else+pokeSockAddr _ SockAddrUnix{} = error "pokeSockAddr: not supported" #endif pokeSockAddr p (SockAddrInet port addr) = do-#if defined(darwin_HOST_OS)     zeroMemory p (#const sizeof(struct sockaddr_in))-#endif #if defined(HAVE_STRUCT_SOCKADDR_SA_LEN)     (#poke struct sockaddr_in, sin_len) p ((#const sizeof(struct sockaddr_in)) :: Word8) #endif     (#poke struct sockaddr_in, sin_family) p ((#const AF_INET) :: CSaFamily)     (#poke struct sockaddr_in, sin_port) p port     (#poke struct sockaddr_in, sin_addr) p addr-#if defined(IPV6_SOCKET_SUPPORT) pokeSockAddr p (SockAddrInet6 port flow addr scope) = do-#if defined(darwin_HOST_OS)     zeroMemory p (#const sizeof(struct sockaddr_in6))-#endif-#if defined(HAVE_STRUCT_SOCKADDR_SA_LEN)+# if defined(HAVE_STRUCT_SOCKADDR_SA_LEN)     (#poke struct sockaddr_in6, sin6_len) p ((#const sizeof(struct sockaddr_in6)) :: Word8)-#endif+# endif     (#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 (In6Addr addr)     (#poke struct sockaddr_in6, sin6_scope_id) p scope-#endif-#if defined(CAN_SOCKET_SUPPORT)-pokeSockAddr p (SockAddrCan ifIndex) = do-#if defined(darwin_HOST_OS)-    zeroMemory p (#const sizeof(struct sockaddr_can))-#endif-    (#poke struct sockaddr_can, can_ifindex) p ifIndex-#endif-#if !(defined(IPV6_SOCKET_SUPPORT) \-      && defined(DOMAIN_SOCKET_SUPPORT) && defined(CAN_SOCKET_SUPPORT))-pokeSockAddr _ _ = error "pokeSockAddr: not supported"-#endif  -- | Read a 'SockAddr' from the given memory location. peekSockAddr :: Ptr SockAddr -> IO SockAddr@@ -976,26 +1013,19 @@   case family :: CSaFamily of #if defined(DOMAIN_SOCKET_SUPPORT)     (#const AF_UNIX) -> do-        str <- peekCString ((#ptr struct sockaddr_un, sun_path) p)+        str <- peekCAString ((#ptr struct sockaddr_un, sun_path) p)         return (SockAddrUnix str) #endif     (#const AF_INET) -> do         addr <- (#peek struct sockaddr_in, sin_addr) p         port <- (#peek struct sockaddr_in, sin_port) p         return (SockAddrInet port addr)-#if defined(IPV6_SOCKET_SUPPORT)     (#const AF_INET6) -> do         port <- (#peek struct sockaddr_in6, sin6_port) p         flow <- (#peek struct sockaddr_in6, sin6_flowinfo) p         In6Addr addr <- (#peek struct sockaddr_in6, sin6_addr) p         scope <- (#peek struct sockaddr_in6, sin6_scope_id) p         return (SockAddrInet6 port flow addr scope)-#endif-#if defined(CAN_SOCKET_SUPPORT)-    (#const AF_CAN) -> do-        ifidx <- (#peek struct sockaddr_can, can_ifindex) p-        return (SockAddrCan ifidx)-#endif     _ -> ioError $ userError $       "Network.Socket.Types.peekSockAddr: address family '" ++       show family ++ "' not supported."@@ -1014,6 +1044,8 @@ -- | 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.+--+{- -- prop> tow == hostAddressToTuple (tupleToHostAddress tow) -} hostAddressToTuple :: HostAddress -> (Word8, Word8, Word8, Word8) hostAddressToTuple ha' =     let ha = htonl ha'@@ -1032,7 +1064,9 @@ -- 'tupleToHostAddress6'. type HostAddress6 = (Word32, Word32, Word32, Word32) -#if defined(IPV6_SOCKET_SUPPORT)+-- | Converts 'HostAddress6' to representation-independent IPv6 octuple.+--+{- -- prop> (w1,w2,w3,w4,w5,w6,w7,w8) == hostAddress6ToTuple (tupleToHostAddress6 (w1,w2,w3,w4,w5,w6,w7,w8)) -} hostAddress6ToTuple :: HostAddress6 -> (Word16, Word16, Word16, Word16,                                         Word16, Word16, Word16, Word16) hostAddress6ToTuple (w3, w2, w1, w0) =@@ -1041,6 +1075,7 @@         low w = fromIntegral w     in (high w3, low w3, high w2, low w2, high w1, low w1, high w0, low w0) +-- | Converts IPv6 octuple to 'HostAddress6'. tupleToHostAddress6 :: (Word16, Word16, Word16, Word16,                         Word16, Word16, Word16, Word16) -> HostAddress6 tupleToHostAddress6 (w7, w6, w5, w4, w3, w2, w1, w0) =@@ -1099,7 +1134,6 @@         poke32 p 1 b         poke32 p 2 c         poke32 p 3 d-#endif  ------------------------------------------------------------------------ -- Helper functions
+ Network/Socket/Unix.hsc view
@@ -0,0 +1,177 @@+{-# LANGUAGE CPP #-}++#include "HsNet.h"+##include "HsNetDef.h"++module Network.Socket.Unix (+    isUnixDomainSocketAvailable+  , socketPair+  , sendFd+  , recvFd+  , getPeerCredential+  , getPeerCred+  , getPeerEid+  ) where++import Network.Socket.Imports+import Network.Socket.Types++#ifdef HAVE_STRUCT_UCRED_SO_PEERCRED+import Foreign.Marshal.Utils (with)+#endif+#ifdef HAVE_GETPEEREID+import qualified Control.Exception as E+import Foreign.Marshal.Alloc (alloca)+#endif+#ifdef DOMAIN_SOCKET_SUPPORT+import Control.Monad (void)+import Foreign.Marshal.Alloc (allocaBytes)+import Foreign.Marshal.Array (peekArray)+import Foreign.Ptr (Ptr)+import Foreign.Storable (Storable(..))++import Network.Socket.Fcntl+import Network.Socket.Internal+#endif+#ifdef HAVE_STRUCT_UCRED_SO_PEERCRED+import Network.Socket.Options (c_getsockopt)+#endif++-- | Getting process ID, user ID and group ID for UNIX-domain sockets.+--+--   This is implemented with SO_PEERCRED on Linux and getpeereid()+--   on BSD variants. Unfortunately, on some BSD variants+--   getpeereid() returns unexpected results, rather than an error,+--   for AF_INET sockets. It is the user's responsibility to make sure+--   that the socket is a UNIX-domain socket.+--   Also, on some BSD variants, getpeereid() does not return credentials+--   for sockets created via 'socketPair', only separately created and then+--   explicitly connected UNIX-domain sockets work on such systems.+--+--   Since 2.7.0.0.+getPeerCredential :: Socket -> IO (Maybe CUInt, Maybe CUInt, Maybe CUInt)+#ifdef HAVE_STRUCT_UCRED_SO_PEERCRED+getPeerCredential sock = do+    (pid, uid, gid) <- getPeerCred sock+    if uid == maxBound then+        return (Nothing, Nothing, Nothing)+      else+        return (Just pid, Just uid, Just gid)+#elif defined(HAVE_GETPEEREID)+getPeerCredential sock = E.handle (\(E.SomeException _) -> return (Nothing,Nothing,Nothing)) $ do+    (uid, gid) <- getPeerEid sock+    return (Nothing, Just uid, Just gid)+#else+getPeerCredential _ = return (Nothing, Nothing, Nothing)+#endif++-- | Returns the processID, userID and groupID of the peer of+--   a UNIX-domain socket.+--+-- Only available on platforms that support SO_PEERCRED.+getPeerCred :: Socket -> IO (CUInt, CUInt, CUInt)+#ifdef HAVE_STRUCT_UCRED_SO_PEERCRED+getPeerCred s = do+  let sz = (#const sizeof(struct ucred))+  fd <- fdSocket s+  allocaBytes sz $ \ ptr_cr ->+   with (fromIntegral sz) $ \ ptr_sz -> do+     _ <- ($) throwSocketErrorIfMinus1Retry "Network.Socket.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+     gid <- (#peek struct ucred, gid) ptr_cr+     return (pid, uid, gid)+#else+getPeerCred _ = return (0, 0, 0)+#endif+{-# Deprecated getPeerCred "Use getPeerCredential instead" #-}++-- | Returns the userID and groupID of the peer of+--   a UNIX-domain socket.+--+--  Only available on platforms that support getpeereid().+getPeerEid :: Socket -> IO (CUInt, CUInt)+#ifdef HAVE_GETPEEREID+getPeerEid s = do+  alloca $ \ ptr_uid ->+    alloca $ \ ptr_gid -> do+      fd <- fdSocket s+      throwSocketErrorIfMinus1Retry_ "Network.Socket.getPeerEid" $+        c_getpeereid fd ptr_uid ptr_gid+      uid <- peek ptr_uid+      gid <- peek ptr_gid+      return (uid, gid)++foreign import CALLCONV unsafe "getpeereid"+  c_getpeereid :: CInt -> Ptr CUInt -> Ptr CUInt -> IO CInt+#else+getPeerEid _ = return (0, 0)+#endif++{-# Deprecated getPeerEid "Use getPeerCredential instead" #-}++-- | Whether or not UNIX-domain sockets are available.+--+--   Since 2.7.0.0.+isUnixDomainSocketAvailable :: Bool+#if defined(DOMAIN_SOCKET_SUPPORT)+isUnixDomainSocketAvailable = True+#else+isUnixDomainSocketAvailable = False+#endif++-- | Send a file descriptor over a UNIX-domain socket.+--   Use this function in the case where 'isUnixDomainSocketAvailable' is+--  'True'.+sendFd :: Socket -> CInt -> IO ()+#if defined(DOMAIN_SOCKET_SUPPORT)+sendFd s outfd = void $ do+  fd <- fdSocket s+  throwSocketErrorWaitWrite s "Network.Socket.sendFd" $ c_sendFd fd outfd+foreign import ccall SAFE_ON_WIN "sendFd" c_sendFd :: CInt -> CInt -> IO CInt+#else+sendFd _ _ = error "Network.Socket.sendFd"+#endif++-- | Receive a file descriptor over a UNIX-domain socket. Note that the resulting+--   file descriptor may have to be put into non-blocking mode in order to be+--   used safely. See 'setNonBlockIfNeeded'.+--   Use this function in the case where 'isUnixDomainSocketAvailable' is+--  'True'.+recvFd :: Socket -> IO CInt+#if defined(DOMAIN_SOCKET_SUPPORT)+recvFd s = do+  fd <- fdSocket s+  throwSocketErrorWaitRead s "Network.Socket.recvFd" $ c_recvFd fd+foreign import ccall SAFE_ON_WIN "recvFd" c_recvFd :: CInt -> IO CInt+#else+recvFd _ = error "Network.Socket.recvFd"+#endif++-- | Build a pair of connected socket objects.+--   For portability, use this function in the case+--   where 'isUnixDomainSocketAvailable' is 'True'+--   and specify 'AF_UNIX' to the first argument.+socketPair :: Family              -- Family Name (usually AF_UNIX)+           -> SocketType          -- Socket Type (usually Stream)+           -> ProtocolNumber      -- Protocol Number+           -> IO (Socket, Socket) -- unnamed and connected.+#if defined(DOMAIN_SOCKET_SUPPORT)+socketPair family stype protocol =+    allocaBytes (2 * sizeOf (1 :: CInt)) $ \ fdArr -> do+      c_stype <- packSocketTypeOrThrow "socketPair" stype+      _rc <- throwSocketErrorIfMinus1Retry "Network.Socket.socketpair" $+                  c_socketpair (packFamily family) c_stype protocol fdArr+      [fd1,fd2] <- peekArray 2 fdArr+      setNonBlockIfNeeded fd1+      setNonBlockIfNeeded fd2+      s1 <- mkSocket fd1+      s2 <- mkSocket fd2+      return (s1, s2)++foreign import ccall unsafe "socketpair"+  c_socketpair :: CInt -> CInt -> CInt -> Ptr CInt -> IO CInt+#else+socketPair _ _ _ = error "Network.Socket.socketPair"+#endif
README.md view
@@ -1,19 +1,66 @@ # [`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-(configure/build/install).  `autoreconf` is included in the-[GNU Autoconf](http://www.gnu.org/software/autoconf/) tools.  There is-no need to run the `configure` script: the `setup configure` step will-do this for you.+To build this package directly from git, you must run `autoreconf -i`.+And then use `cabal configure; cabal build` or `stack build`.  ## Support Policy  ### GHC -`network`'s GHC policy supports 3 [stable](https://downloads.haskell.org/~ghc/8.0.2/docs/html/users_guide/intro.html#ghc-version-numbering-policy) versions. The current stable-version and two previous stable versions are supported.+The `network` package support [3 major versions of GHC](https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/intro.html#ghc-version-numbering-policy) only.+This means that the current stable version and two previous stable versions are supported. -### Hugs, JHC, UHC+### Windows -`network` does not officially support these compilers.+We use MSYS to build this package on Windows.+To use the `network` package on Cygwin, use `stack`.++## Coding++### .hs files++If you need C macros created by "configure" or `CALLCONV`/`SAFE_ON_WIN`, put++```+#include "HsNetDef.h"+```++"HsNet.h" does now work well since Mac's cpp sucks.++### .hsc files++If you need `#peek`, `#poke` and others, create a `.hsc` file with++```+#include "HsNet.h"+```++`HsNet.h` includes `HsNefDef.h` and necessary C structures.+Unfortunately, `hsc2hs` does not convert C macros.+So, if you use `CALLCONV`/`SAFE_ON_WIN`, the following is also necessary:++```+##include "HsNetDef.h"+```++## Milestones++### 2.6++- [x] Making `SockAddrCan` deprecated++### 2.7++See https://github.com/haskell/network/issues/296++- Making `Network` deprecated+- Making `Network.BSD` deprecated+- Making `MkSocket` deprecated+- Making many APIs deprecated++### 3.0++- Removing `Network`+- Removing `Network.BSD`+- Removing `SockAddrCan`+- Changing the internal structure of `Socket`.
cbits/asyncAccept.c view
@@ -5,14 +5,14 @@ #include "HsNet.h" #include "HsFFI.h" -#if defined(HAVE_WINSOCK2_H)+#if defined(_WIN32)  /* all the way to the end */  /*  * To support non-blocking accept()s with WinSock, we use the asyncDoProc#  * primop, which lets a Haskell thread call an external routine without- * blocking the progress of other threads. + * blocking the progress of other threads.  *  * As can readily be seen, this is a low-level mechanism.  *@@ -26,7 +26,7 @@ } AcceptData;  /*- * Fill in parameter block that's passed along when the RTS invokes the + * Fill in parameter block that's passed along when the RTS invokes the  * accept()-calling proc below (acceptDoProc())  */ void*@@ -40,7 +40,7 @@     data->newSock  = 0;     data->sockAddr = sockaddr;     data->size     = sz;-    +     return data; } 
cbits/initWinSock.c view
@@ -1,7 +1,7 @@ #include "HsNet.h" #include "HsFFI.h" -#if defined(HAVE_WINSOCK2_H)+#if defined(_WIN32)  static int winsock_inited = 0; @@ -16,14 +16,14 @@ initWinSock () {   WORD wVersionRequested;-  WSADATA wsaData;  +  WSADATA wsaData;   int err;    if (!winsock_inited) {     wVersionRequested = MAKEWORD( 2, 2 );      err = WSAStartup ( wVersionRequested, &wsaData );-    +     if ( err != 0 ) {        return err;     }
cbits/winSockErr.c view
@@ -1,7 +1,7 @@ #include "HsNet.h" #include "HsFFI.h" -#if defined(HAVE_WINSOCK2_H)+#if defined(_WIN32) #include <stdio.h>  /* to the end */
configure view
@@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles.-# Generated by GNU Autoconf 2.69 for Haskell network package 2.8.0.1.+# Generated by GNU Autoconf 2.69 for Haskell network package 3.0.0.0. # # Report bugs to <libraries@haskell.org>. #@@ -580,8 +580,8 @@ # Identity of this package. PACKAGE_NAME='Haskell network package' PACKAGE_TARNAME='network'-PACKAGE_VERSION='2.8.0.1'-PACKAGE_STRING='Haskell network package 2.8.0.1'+PACKAGE_VERSION='3.0.0.0'+PACKAGE_STRING='Haskell network package 3.0.0.0' PACKAGE_BUGREPORT='libraries@haskell.org' PACKAGE_URL='' @@ -624,9 +624,6 @@  ac_subst_vars='LTLIBOBJS LIBOBJS-EXTRA_SRCS-EXTRA_LIBS-EXTRA_CPPFLAGS EGREP GREP CPP@@ -1248,7 +1245,7 @@   # Omit some internal or obsolete options to make the list less imposing.   # This message is too long to be a string in the A/UX 3.1 sh.   cat <<_ACEOF-\`configure' configures Haskell network package 2.8.0.1 to adapt to many kinds of systems.+\`configure' configures Haskell network package 3.0.0.0 to adapt to many kinds of systems.  Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1314,7 +1311,7 @@  if test -n "$ac_init_help"; then   case $ac_init_help in-     short | recursive ) echo "Configuration of Haskell network package 2.8.0.1:";;+     short | recursive ) echo "Configuration of Haskell network package 3.0.0.0:";;    esac   cat <<\_ACEOF @@ -1399,7 +1396,7 @@ test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then   cat <<\_ACEOF-Haskell network package configure 2.8.0.1+Haskell network package configure 3.0.0.0 generated by GNU Autoconf 2.69  Copyright (C) 2012 Free Software Foundation, Inc.@@ -1652,6 +1649,60 @@  } # ac_fn_c_check_header_compile +# ac_fn_c_check_type LINENO TYPE VAR INCLUDES+# -------------------------------------------+# Tests whether TYPE exists after having included INCLUDES, setting cache+# variable VAR accordingly.+ac_fn_c_check_type ()+{+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5+$as_echo_n "checking for $2... " >&6; }+if eval \${$3+:} false; then :+  $as_echo_n "(cached) " >&6+else+  eval "$3=no"+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext+/* end confdefs.h.  */+$4+int+main ()+{+if (sizeof ($2))+	 return 0;+  ;+  return 0;+}+_ACEOF+if ac_fn_c_try_compile "$LINENO"; then :+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext+/* end confdefs.h.  */+$4+int+main ()+{+if (sizeof (($2)))+	    return 0;+  ;+  return 0;+}+_ACEOF+if ac_fn_c_try_compile "$LINENO"; then :++else+  eval "$3=yes"+fi+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext+fi+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext+fi+eval ac_res=\$$3+	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5+$as_echo "$ac_res" >&6; }+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno++} # ac_fn_c_check_type+ # ac_fn_c_try_link LINENO # ----------------------- # Try to link conftest.$ac_ext, and return whether this succeeded.@@ -1765,6 +1816,52 @@  } # ac_fn_c_check_func +# ac_fn_c_check_decl LINENO SYMBOL VAR INCLUDES+# ---------------------------------------------+# Tests whether SYMBOL is declared in INCLUDES, setting cache variable VAR+# accordingly.+ac_fn_c_check_decl ()+{+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack+  as_decl_name=`echo $2|sed 's/ *(.*//'`+  as_decl_use=`echo $2|sed -e 's/(/((/' -e 's/)/) 0&/' -e 's/,/) 0& (/g'`+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $as_decl_name is declared" >&5+$as_echo_n "checking whether $as_decl_name is declared... " >&6; }+if eval \${$3+:} false; then :+  $as_echo_n "(cached) " >&6+else+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext+/* end confdefs.h.  */+$4+int+main ()+{+#ifndef $as_decl_name+#ifdef __cplusplus+  (void) $as_decl_use;+#else+  (void) $as_decl_name;+#endif+#endif++  ;+  return 0;+}+_ACEOF+if ac_fn_c_try_compile "$LINENO"; then :+  eval "$3=yes"+else+  eval "$3=no"+fi+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext+fi+eval ac_res=\$$3+	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5+$as_echo "$ac_res" >&6; }+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno++} # ac_fn_c_check_decl+ # ac_fn_c_check_member LINENO AGGR MEMBER VAR INCLUDES # ---------------------------------------------------- # Tries to find if the field MEMBER exists in type AGGR, after including@@ -1821,57 +1918,11 @@   eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno  } # ac_fn_c_check_member--# ac_fn_c_check_decl LINENO SYMBOL VAR INCLUDES-# ----------------------------------------------# Tests whether SYMBOL is declared in INCLUDES, setting cache variable VAR-# accordingly.-ac_fn_c_check_decl ()-{-  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack-  as_decl_name=`echo $2|sed 's/ *(.*//'`-  as_decl_use=`echo $2|sed -e 's/(/((/' -e 's/)/) 0&/' -e 's/,/) 0& (/g'`-  { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $as_decl_name is declared" >&5-$as_echo_n "checking whether $as_decl_name is declared... " >&6; }-if eval \${$3+:} false; then :-  $as_echo_n "(cached) " >&6-else-  cat confdefs.h - <<_ACEOF >conftest.$ac_ext-/* end confdefs.h.  */-$4-int-main ()-{-#ifndef $as_decl_name-#ifdef __cplusplus-  (void) $as_decl_use;-#else-  (void) $as_decl_name;-#endif-#endif--  ;-  return 0;-}-_ACEOF-if ac_fn_c_try_compile "$LINENO"; then :-  eval "$3=yes"-else-  eval "$3=no"-fi-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext-fi-eval ac_res=\$$3-	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5-$as_echo "$ac_res" >&6; }-  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno--} # ac_fn_c_check_decl cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by Haskell network package $as_me 2.8.0.1, which was+It was created by Haskell network package $as_me 3.0.0.0, which was generated by GNU Autoconf 2.69.  Invocation command line was    $ $0 $@@@ -2220,26 +2271,59 @@   -ac_includes_default="$ac_includes_default+ac_includes_default="#define _GNU_SOURCE 1  /* for struct ucred on Linux */+$ac_includes_default++#ifdef _WIN32+# include <winsock2.h>+# include <ws2tcpip.h>+# define IPV6_V6ONLY 27+#endif++#ifdef HAVE_LIMITS_H+# include <limits.h>+#endif+#ifdef HAVE_STDLIB_H+# include <stdlib.h>+#endif+#ifdef HAVE_UNISTD_H+#include <unistd.h>+#endif+#ifdef HAVE_SYS_TYPES_H+# include <sys/types.h>+#endif+#ifdef HAVE_FCNTL_H+# include <fcntl.h>+#endif+#ifdef HAVE_SYS_UIO_H+# include <sys/uio.h>+#endif #ifdef HAVE_SYS_SOCKET_H # include <sys/socket.h> #endif #ifdef HAVE_NETINET_IN_H # include <netinet/in.h> #endif+#ifdef HAVE_NETINET_TCP_H+# include <netinet/tcp.h>+#endif+#ifdef HAVE_SYS_UN_H+# include <sys/un.h>+#endif+#ifdef HAVE_ARPA_INET_H+# include <arpa/inet.h>+#endif #ifdef HAVE_NETDB_H-# include <netdb.h>+#include <netdb.h> #endif-#ifdef HAVE_WINSOCK2_H-# include <winsock2.h>+#ifdef HAVE_NET_IF_H+# include <net/if.h> #endif-#ifdef HAVE_WS2TCPIP_H-# include <ws2tcpip.h>-// fix for MingW not defining IPV6_V6ONLY-# define IPV6_V6ONLY 27-#endif"+#ifdef HAVE_NETIOAPI_H+# include <netioapi.h>+#endif+" -# Safety check: Ensure that we are in the correct source directory.   ac_config_headers="$ac_config_headers include/HsNetworkConfig.h"@@ -3622,7 +3706,7 @@ done  -for ac_header in fcntl.h limits.h stdlib.h sys/types.h unistd.h winsock2.h ws2tcpip.h+for ac_header in limits.h stdlib.h unistd.h sys/types.h fcntl.h do :   as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"@@ -3635,7 +3719,7 @@  done -for ac_header in arpa/inet.h netdb.h netinet/in.h netinet/tcp.h sys/socket.h sys/uio.h sys/un.h linux/can.h linux/tcp.h+for ac_header in sys/uio.h sys/socket.h netinet/in.h netinet/tcp.h do :   as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"@@ -3648,294 +3732,62 @@  done -for ac_header in net/if.h+for ac_header in sys/un.h arpa/inet.h netdb.h do :-  ac_fn_c_check_header_mongrel "$LINENO" "net/if.h" "ac_cv_header_net_if_h" "$ac_includes_default"-if test "x$ac_cv_header_net_if_h" = xyes; then :+  as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`+ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :   cat >>confdefs.h <<_ACEOF-#define HAVE_NET_IF_H 1+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF  fi  done --for ac_func in readlink symlink if_nametoindex+for ac_header in net/if.h netioapi.h do :-  as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`-ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"-if eval test \"x\$"$as_ac_var"\" = x"yes"; then :+  as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`+ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :   cat >>confdefs.h <<_ACEOF-#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF  fi-done --ac_fn_c_check_member "$LINENO" "struct msghdr" "msg_control" "ac_cv_member_struct_msghdr_msg_control" "#if HAVE_SYS_TYPES_H-# include <sys/types.h>-#endif-#if HAVE_SYS_SOCKET_H-# include <sys/socket.h>-#endif-#if HAVE_SYS_UIO_H-# include <sys/uio.h>-#endif-"-if test "x$ac_cv_member_struct_msghdr_msg_control" = xyes; then :--cat >>confdefs.h <<_ACEOF-#define HAVE_STRUCT_MSGHDR_MSG_CONTROL 1-_ACEOF---fi-ac_fn_c_check_member "$LINENO" "struct msghdr" "msg_accrights" "ac_cv_member_struct_msghdr_msg_accrights" "#if HAVE_SYS_TYPES_H-# include <sys/types.h>-#endif-#if HAVE_SYS_SOCKET_H-# include <sys/socket.h>-#endif-#if HAVE_SYS_UIO_H-# include <sys/uio.h>-#endif-"-if test "x$ac_cv_member_struct_msghdr_msg_accrights" = xyes; then :--cat >>confdefs.h <<_ACEOF-#define HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS 1-_ACEOF---fi+done  -ac_fn_c_check_member "$LINENO" "struct sockaddr" "sa_len" "ac_cv_member_struct_sockaddr_sa_len" "#if HAVE_SYS_TYPES_H-# include <sys/types.h>-#endif-#if HAVE_SYS_SOCKET_H-# include <sys/socket.h>-#endif-"-if test "x$ac_cv_member_struct_sockaddr_sa_len" = xyes; then :+ac_fn_c_check_type "$LINENO" "struct ucred" "ac_cv_type_struct_ucred" "$ac_includes_default"+if test "x$ac_cv_type_struct_ucred" = xyes; then :  cat >>confdefs.h <<_ACEOF-#define HAVE_STRUCT_SOCKADDR_SA_LEN 1+#define HAVE_STRUCT_UCRED 1 _ACEOF   fi  -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for in_addr_t in netinet/in.h" >&5-$as_echo_n "checking for in_addr_t in netinet/in.h... " >&6; }-cat confdefs.h - <<_ACEOF >conftest.$ac_ext-/* end confdefs.h.  */-#include <netinet/in.h>--_ACEOF-if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |-  $EGREP "in_addr_t" >/dev/null 2>&1; then :--$as_echo "#define HAVE_IN_ADDR_T 1" >>confdefs.h- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5-$as_echo "yes" >&6; }-else-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5-$as_echo "no" >&6; }-fi-rm -f conftest*---{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for SO_PEERCRED and struct ucred in sys/socket.h" >&5-$as_echo_n "checking for SO_PEERCRED and struct ucred in sys/socket.h... " >&6; }-cat confdefs.h - <<_ACEOF >conftest.$ac_ext-/* end confdefs.h.  */-#include <sys/types.h>-#include <sys/socket.h>-#ifndef SO_PEERCRED-# error no SO_PEERCRED-#endif-struct ucred u;-int-main ()-{--  ;-  return 0;-}-_ACEOF-if ac_fn_c_try_compile "$LINENO"; then :-  ac_cv_ucred=yes-else-  ac_cv_ucred=no-fi-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext-if test "x$ac_cv_ucred" = xno; then-    old_CFLAGS="$CFLAGS"-    CFLAGS="-D_GNU_SOURCE $CFLAGS"-    cat confdefs.h - <<_ACEOF >conftest.$ac_ext-/* end confdefs.h.  */-#include <sys/types.h>-#include <sys/socket.h>-#ifndef SO_PEERCRED-# error no SO_PEERCRED-#endif-struct ucred u;-int-main ()-{--  ;-  return 0;-}-_ACEOF-if ac_fn_c_try_compile "$LINENO"; then :-  ac_cv_ucred=yes-else-  ac_cv_ucred=no-fi-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext-    if test "x$ac_cv_ucred" = xyes; then-        EXTRA_CPPFLAGS=-D_GNU_SOURCE-    fi-else-    old_CFLAGS="$CFLAGS"-fi-if test "x$ac_cv_ucred" = xno; then-    CFLAGS="$old_CFLAGS"-    { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5-$as_echo "no" >&6; }-else--$as_echo "#define HAVE_STRUCT_UCRED 1" >>confdefs.h--    { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5-$as_echo "yes" >&6; }-fi--{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for getpeereid in unistd.h" >&5-$as_echo_n "checking for getpeereid in unistd.h... " >&6; }-ac_fn_c_check_func "$LINENO" "getpeereid" "ac_cv_func_getpeereid"-if test "x$ac_cv_func_getpeereid" = xyes; then :--$as_echo "#define HAVE_GETPEEREID 1" >>confdefs.h--fi---{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for _head_libws2_32_a in -lws2_32" >&5-$as_echo_n "checking for _head_libws2_32_a in -lws2_32... " >&6; }-if ${ac_cv_lib_ws2_32__head_libws2_32_a+:} false; then :-  $as_echo_n "(cached) " >&6-else-  ac_check_lib_save_LIBS=$LIBS-LIBS="-lws2_32  $LIBS"-cat confdefs.h - <<_ACEOF >conftest.$ac_ext-/* end confdefs.h.  */--/* Override any GCC internal prototype to avoid an error.-   Use char because int might match the return type of a GCC-   builtin and then its argument prototype would still apply.  */-#ifdef __cplusplus-extern "C"-#endif-char _head_libws2_32_a ();-int-main ()-{-return _head_libws2_32_a ();-  ;-  return 0;-}-_ACEOF-if ac_fn_c_try_link "$LINENO"; then :-  ac_cv_lib_ws2_32__head_libws2_32_a=yes-else-  ac_cv_lib_ws2_32__head_libws2_32_a=no-fi-rm -f core conftest.err conftest.$ac_objext \-    conftest$ac_exeext conftest.$ac_ext-LIBS=$ac_check_lib_save_LIBS-fi-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ws2_32__head_libws2_32_a" >&5-$as_echo "$ac_cv_lib_ws2_32__head_libws2_32_a" >&6; }-if test "x$ac_cv_lib_ws2_32__head_libws2_32_a" = xyes; then :+for ac_func in gai_strerror gethostent accept4+do :+  as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`+ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"+if eval test \"x\$"$as_ac_var"\" = x"yes"; then :   cat >>confdefs.h <<_ACEOF-#define HAVE_LIBWS2_32 1+#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF -  LIBS="-lws2_32 $LIBS"- fi---{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for getaddrinfo" >&5-$as_echo_n "checking for getaddrinfo... " >&6; }-cat confdefs.h - <<_ACEOF >conftest.$ac_ext-/* end confdefs.h.  */-$ac_includes_default-int testme(){ getaddrinfo; }-int-main ()-{--  ;-  return 0;-}-_ACEOF-if ac_fn_c_try_compile "$LINENO"; then :--$as_echo "#define HAVE_GETADDRINFO 1" >>confdefs.h- ac_have_getaddrinfo=yes; { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5-$as_echo "yes" >&6; }-else-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5-$as_echo "no" >&6; }-fi-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext--if test "x$ac_have_getaddrinfo" = x; then-  old_CFLAGS="$CFLAGS"-  if test "z$ac_cv_lib_ws2_32__head_libws2_32_a" = zyes; then-    CFLAGS="-DWINVER=0x0501 $CFLAGS"-    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for getaddrinfo if WINVER is 0x0501" >&5-$as_echo_n "checking for getaddrinfo if WINVER is 0x0501... " >&6; }-    cat confdefs.h - <<_ACEOF >conftest.$ac_ext-/* end confdefs.h.  */-$ac_includes_default-    int testme(){ getaddrinfo; }-int-main ()-{--  ;-  return 0;-}-_ACEOF-if ac_fn_c_try_compile "$LINENO"; then :--$as_echo "#define HAVE_GETADDRINFO 1" >>confdefs.h--$as_echo "#define NEED_WINVER_XP 1" >>confdefs.h- EXTRA_CPPFLAGS="-DWINVER=0x0501 $EXTRA_CPPFLAGS"; { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5-$as_echo "yes" >&6; }-else-  CFLAGS="$old_CFLAGS"; { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5-$as_echo "no" >&6; }-fi-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext-  fi-fi+done -for ac_func in gai_strerror+for ac_func in getpeereid do :-  ac_fn_c_check_func "$LINENO" "gai_strerror" "ac_cv_func_gai_strerror"-if test "x$ac_cv_func_gai_strerror" = xyes; then :+  ac_fn_c_check_func "$LINENO" "getpeereid" "ac_cv_func_getpeereid"+if test "x$ac_cv_func_getpeereid" = xyes; then :   cat >>confdefs.h <<_ACEOF-#define HAVE_GAI_STRERROR 1+#define HAVE_GETPEEREID 1 _ACEOF  fi@@ -3983,7 +3835,6 @@ #define HAVE_DECL_AI_V4MAPPED $ac_have_decl _ACEOF - ac_fn_c_check_decl "$LINENO" "IPV6_V6ONLY" "ac_cv_have_decl_IPV6_V6ONLY" "$ac_includes_default" if test "x$ac_cv_have_decl_IPV6_V6ONLY" = xyes; then :   ac_have_decl=1@@ -3995,7 +3846,6 @@ #define HAVE_DECL_IPV6_V6ONLY $ac_have_decl _ACEOF - ac_fn_c_check_decl "$LINENO" "IPPROTO_IP" "ac_cv_have_decl_IPPROTO_IP" "$ac_includes_default" if test "x$ac_cv_have_decl_IPPROTO_IP" = xyes; then :   ac_have_decl=1@@ -4027,91 +3877,51 @@ #define HAVE_DECL_IPPROTO_IPV6 $ac_have_decl _ACEOF --{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for sendfile in sys/sendfile.h" >&5-$as_echo_n "checking for sendfile in sys/sendfile.h... " >&6; }-cat confdefs.h - <<_ACEOF >conftest.$ac_ext-/* end confdefs.h.  */-#include <sys/sendfile.h>--_ACEOF-if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |-  $EGREP "sendfile" >/dev/null 2>&1; then :--$as_echo "#define HAVE_LINUX_SENDFILE 1" >>confdefs.h- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5-$as_echo "yes" >&6; }+ac_fn_c_check_decl "$LINENO" "SO_PEERCRED" "ac_cv_have_decl_SO_PEERCRED" "$ac_includes_default"+if test "x$ac_cv_have_decl_SO_PEERCRED" = xyes; then :+  ac_have_decl=1 else-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5-$as_echo "no" >&6; }+  ac_have_decl=0 fi-rm -f conftest* --{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for sendfile in sys/socket.h" >&5-$as_echo_n "checking for sendfile in sys/socket.h... " >&6; }-cat confdefs.h - <<_ACEOF >conftest.$ac_ext-/* end confdefs.h.  */-#include <sys/socket.h>-+cat >>confdefs.h <<_ACEOF+#define HAVE_DECL_SO_PEERCRED $ac_have_decl _ACEOF-if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |-  $EGREP "sendfile" >/dev/null 2>&1; then : -$as_echo "#define HAVE_BSD_SENDFILE 1" >>confdefs.h- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5-$as_echo "yes" >&6; }-else-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5-$as_echo "no" >&6; }-fi-rm -f conftest* +ac_fn_c_check_member "$LINENO" "struct msghdr" "msg_control" "ac_cv_member_struct_msghdr_msg_control" "$ac_includes_default"+if test "x$ac_cv_member_struct_msghdr_msg_control" = xyes; then : -for ac_func in gethostent-do :-  ac_fn_c_check_func "$LINENO" "gethostent" "ac_cv_func_gethostent"-if test "x$ac_cv_func_gethostent" = xyes; then :-  cat >>confdefs.h <<_ACEOF-#define HAVE_GETHOSTENT 1+cat >>confdefs.h <<_ACEOF+#define HAVE_STRUCT_MSGHDR_MSG_CONTROL 1 _ACEOF -fi-done +fi+ac_fn_c_check_member "$LINENO" "struct msghdr" "msg_accrights" "ac_cv_member_struct_msghdr_msg_accrights" "$ac_includes_default"+if test "x$ac_cv_member_struct_msghdr_msg_accrights" = xyes; then : -for ac_func in accept4-do :-  ac_fn_c_check_func "$LINENO" "accept4" "ac_cv_func_accept4"-if test "x$ac_cv_func_accept4" = xyes; then :-  cat >>confdefs.h <<_ACEOF-#define HAVE_ACCEPT4 1+cat >>confdefs.h <<_ACEOF+#define HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS 1 _ACEOF + fi-done +ac_fn_c_check_member "$LINENO" "struct sockaddr" "sa_len" "ac_cv_member_struct_sockaddr_sa_len" "$ac_includes_default"+if test "x$ac_cv_member_struct_sockaddr_sa_len" = xyes; then : -case "$host" in-*-mingw* | *-msys*)-	EXTRA_SRCS="cbits/initWinSock.c, cbits/winSockErr.c, cbits/asyncAccept.c"-	EXTRA_LIBS=ws2_32-	;;-*-solaris2*)-	EXTRA_SRCS="cbits/ancilData.c"-	EXTRA_LIBS="nsl, socket"-	;;-*)-	EXTRA_SRCS="cbits/ancilData.c"-	EXTRA_LIBS=-	;;-esac+cat >>confdefs.h <<_ACEOF+#define HAVE_STRUCT_SOCKADDR_SA_LEN 1+_ACEOF  +fi  -ac_config_files="$ac_config_files network.buildinfo"-+{ $as_echo "$as_me:${as_lineno-$LINENO}: creating ./network.buildinfo" >&5+$as_echo "$as_me: creating ./network.buildinfo" >&6;}+echo "install-includes: HsNetworkConfig.h" > network.buildinfo  cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure@@ -4619,7 +4429,7 @@ # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log="-This file was extended by Haskell network package $as_me 2.8.0.1, which was+This file was extended by Haskell network package $as_me 3.0.0.0, which was generated by GNU Autoconf 2.69.  Invocation command line was    CONFIG_FILES    = $CONFIG_FILES@@ -4633,9 +4443,6 @@  _ACEOF -case $ac_config_files in *"-"*) set x $ac_config_files; shift; ac_config_files=$*;;-esac  case $ac_config_headers in *" "*) set x $ac_config_headers; shift; ac_config_headers=$*;;@@ -4644,7 +4451,6 @@  cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # Files that config.status was made for.-config_files="$ac_config_files" config_headers="$ac_config_headers"  _ACEOF@@ -4664,14 +4470,9 @@                    do not print progress messages   -d, --debug      don't remove temporary files       --recheck    update $as_me by reconfiguring in the same conditions-      --file=FILE[:TEMPLATE]-                   instantiate the configuration file FILE       --header=FILE[:TEMPLATE]                    instantiate the configuration header FILE -Configuration files:-$config_files- Configuration headers: $config_headers @@ -4681,7 +4482,7 @@ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\-Haskell network package config.status 2.8.0.1+Haskell network package config.status 3.0.0.0 configured by $0, generated by GNU Autoconf 2.69,   with options \\"\$ac_cs_config\\" @@ -4727,14 +4528,6 @@     $as_echo "$ac_cs_config"; exit ;;   --debug | --debu | --deb | --de | --d | -d )     debug=: ;;-  --file | --fil | --fi | --f )-    $ac_shift-    case $ac_optarg in-    *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;-    '') as_fn_error $? "missing file argument" ;;-    esac-    as_fn_append CONFIG_FILES " '$ac_optarg'"-    ac_need_defaults=false;;   --header | --heade | --head | --hea )     $ac_shift     case $ac_optarg in@@ -4803,7 +4596,6 @@ do   case $ac_config_target in     "include/HsNetworkConfig.h") CONFIG_HEADERS="$CONFIG_HEADERS include/HsNetworkConfig.h" ;;-    "network.buildinfo") CONFIG_FILES="$CONFIG_FILES network.buildinfo" ;;    *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;   esac@@ -4815,7 +4607,6 @@ # We use the long form for the default assignment because of an extremely # bizarre bug on SunOS 4.1.3. if $ac_need_defaults; then-  test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files   test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers fi @@ -4846,164 +4637,6 @@ } || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 ac_tmp=$tmp -# Set up the scripts for CONFIG_FILES section.-# No need to generate them if there are no CONFIG_FILES.-# This happens for instance with `./config.status config.h'.-if test -n "$CONFIG_FILES"; then---ac_cr=`echo X | tr X '\015'`-# On cygwin, bash can eat \r inside `` if the user requested igncr.-# But we know of no other shell where ac_cr would be empty at this-# point, so we can use a bashism as a fallback.-if test "x$ac_cr" = x; then-  eval ac_cr=\$\'\\r\'-fi-ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null`-if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then-  ac_cs_awk_cr='\\r'-else-  ac_cs_awk_cr=$ac_cr-fi--echo 'BEGIN {' >"$ac_tmp/subs1.awk" &&-_ACEOF---{-  echo "cat >conf$$subs.awk <<_ACEOF" &&-  echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' &&-  echo "_ACEOF"-} >conf$$subs.sh ||-  as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5-ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'`-ac_delim='%!_!# '-for ac_last_try in false false false false false :; do-  . ./conf$$subs.sh ||-    as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5--  ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X`-  if test $ac_delim_n = $ac_delim_num; then-    break-  elif $ac_last_try; then-    as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5-  else-    ac_delim="$ac_delim!$ac_delim _$ac_delim!! "-  fi-done-rm -f conf$$subs.sh--cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1-cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK &&-_ACEOF-sed -n '-h-s/^/S["/; s/!.*/"]=/-p-g-s/^[^!]*!//-:repl-t repl-s/'"$ac_delim"'$//-t delim-:nl-h-s/\(.\{148\}\)..*/\1/-t more1-s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/-p-n-b repl-:more1-s/["\\]/\\&/g; s/^/"/; s/$/"\\/-p-g-s/.\{148\}//-t nl-:delim-h-s/\(.\{148\}\)..*/\1/-t more2-s/["\\]/\\&/g; s/^/"/; s/$/"/-p-b-:more2-s/["\\]/\\&/g; s/^/"/; s/$/"\\/-p-g-s/.\{148\}//-t delim-' <conf$$subs.awk | sed '-/^[^""]/{-  N-  s/\n//-}-' >>$CONFIG_STATUS || ac_write_fail=1-rm -f conf$$subs.awk-cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1-_ACAWK-cat >>"\$ac_tmp/subs1.awk" <<_ACAWK &&-  for (key in S) S_is_set[key] = 1-  FS = ""--}-{-  line = $ 0-  nfields = split(line, field, "@")-  substed = 0-  len = length(field[1])-  for (i = 2; i < nfields; i++) {-    key = field[i]-    keylen = length(key)-    if (S_is_set[key]) {-      value = S[key]-      line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3)-      len += length(value) + length(field[++i])-      substed = 1-    } else-      len += 1 + keylen-  }--  print line-}--_ACAWK-_ACEOF-cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1-if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then-  sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g"-else-  cat-fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \-  || as_fn_error $? "could not setup config files machinery" "$LINENO" 5-_ACEOF--# VPATH may cause trouble with some makes, so we remove sole $(srcdir),-# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and-# trailing colons and then remove the whole line if VPATH becomes empty-# (actually we leave an empty line to preserve line numbers).-if test "x$srcdir" = x.; then-  ac_vpsub='/^[	 ]*VPATH[	 ]*=[	 ]*/{-h-s///-s/^/:/-s/[	 ]*$/:/-s/:\$(srcdir):/:/g-s/:\${srcdir}:/:/g-s/:@srcdir@:/:/g-s/^:*//-s/:*$//-x-s/\(=[	 ]*\).*/\1/-G-s/\n//-s/^[^=]*=[	 ]*$//-}'-fi--cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1-fi # test -n "$CONFIG_FILES"- # Set up the scripts for CONFIG_HEADERS section. # No need to generate them if there are no CONFIG_HEADERS. # This happens for instance with `./config.status Makefile'.@@ -5113,7 +4746,7 @@ fi # test -n "$CONFIG_HEADERS"  -eval set X "  :F $CONFIG_FILES  :H $CONFIG_HEADERS    "+eval set X "    :H $CONFIG_HEADERS    " shift for ac_tag do@@ -5242,85 +4875,7 @@     case $ac_mode in-  :F)-  #-  # CONFIG_FILE-  # -_ACEOF--cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1-# If the template does not know about datarootdir, expand it.-# FIXME: This hack should be removed a few years after 2.60.-ac_datarootdir_hack=; ac_datarootdir_seen=-ac_sed_dataroot='-/datarootdir/ {-  p-  q-}-/@datadir@/p-/@docdir@/p-/@infodir@/p-/@localedir@/p-/@mandir@/p'-case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in-*datarootdir*) ac_datarootdir_seen=yes;;-*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*)-  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5-$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;}-_ACEOF-cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1-  ac_datarootdir_hack='-  s&@datadir@&$datadir&g-  s&@docdir@&$docdir&g-  s&@infodir@&$infodir&g-  s&@localedir@&$localedir&g-  s&@mandir@&$mandir&g-  s&\\\${datarootdir}&$datarootdir&g' ;;-esac-_ACEOF--# Neutralize VPATH when `$srcdir' = `.'.-# Shell code in configure.ac might set extrasub.-# FIXME: do we really want to maintain this feature?-cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1-ac_sed_extra="$ac_vpsub-$extrasub-_ACEOF-cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1-:t-/@[a-zA-Z_][a-zA-Z_0-9]*@/!b-s|@configure_input@|$ac_sed_conf_input|;t t-s&@top_builddir@&$ac_top_builddir_sub&;t t-s&@top_build_prefix@&$ac_top_build_prefix&;t t-s&@srcdir@&$ac_srcdir&;t t-s&@abs_srcdir@&$ac_abs_srcdir&;t t-s&@top_srcdir@&$ac_top_srcdir&;t t-s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t-s&@builddir@&$ac_builddir&;t t-s&@abs_builddir@&$ac_abs_builddir&;t t-s&@abs_top_builddir@&$ac_abs_top_builddir&;t t-$ac_datarootdir_hack-"-eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \-  >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5--test -z "$ac_datarootdir_hack$ac_datarootdir_seen" &&-  { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } &&-  { ac_out=`sed -n '/^[	 ]*datarootdir[	 ]*:*=/p' \-      "$ac_tmp/out"`; test -z "$ac_out"; } &&-  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir'-which seems to be undefined.  Please make sure it is defined" >&5-$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir'-which seems to be undefined.  Please make sure it is defined" >&2;}--  rm -f "$ac_tmp/stdin"-  case $ac_file in-  -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";;-  *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";;-  esac \-  || as_fn_error $? "could not create $ac_file" "$LINENO" 5- ;;   :H)   #   # CONFIG_HEADER
configure.ac view
@@ -1,25 +1,62 @@-AC_INIT([Haskell network package], [2.8.0.1], [libraries@haskell.org], [network])+AC_INIT([Haskell network package],+        [3.0.0.0],+        [libraries@haskell.org],+        [network]) -ac_includes_default="$ac_includes_default+dnl See also HsNet.h+ac_includes_default="#define _GNU_SOURCE 1  /* for struct ucred on Linux */+$ac_includes_default++#ifdef _WIN32+# include <winsock2.h>+# include <ws2tcpip.h>+# define IPV6_V6ONLY 27+#endif++#ifdef HAVE_LIMITS_H+# include <limits.h>+#endif+#ifdef HAVE_STDLIB_H+# include <stdlib.h>+#endif+#ifdef HAVE_UNISTD_H+#include <unistd.h>+#endif+#ifdef HAVE_SYS_TYPES_H+# include <sys/types.h>+#endif+#ifdef HAVE_FCNTL_H+# include <fcntl.h>+#endif+#ifdef HAVE_SYS_UIO_H+# include <sys/uio.h>+#endif #ifdef HAVE_SYS_SOCKET_H # include <sys/socket.h> #endif #ifdef HAVE_NETINET_IN_H # include <netinet/in.h> #endif+#ifdef HAVE_NETINET_TCP_H+# include <netinet/tcp.h>+#endif+#ifdef HAVE_SYS_UN_H+# include <sys/un.h>+#endif+#ifdef HAVE_ARPA_INET_H+# include <arpa/inet.h>+#endif #ifdef HAVE_NETDB_H-# include <netdb.h>+#include <netdb.h> #endif-#ifdef HAVE_WINSOCK2_H-# include <winsock2.h>+#ifdef HAVE_NET_IF_H+# include <net/if.h> #endif-#ifdef HAVE_WS2TCPIP_H-# include <ws2tcpip.h>-// fix for MingW not defining IPV6_V6ONLY-# define IPV6_V6ONLY 27-#endif"+#ifdef HAVE_NETIOAPI_H+# include <netioapi.h>+#endif+" -# Safety check: Ensure that we are in the correct source directory. AC_CONFIG_SRCDIR([include/HsNet.h])  AC_CONFIG_HEADERS([include/HsNetworkConfig.h])@@ -33,160 +70,26 @@  AC_C_CONST -dnl ** check for specific header (.h) files that we are interested in-AC_CHECK_HEADERS([fcntl.h limits.h stdlib.h sys/types.h unistd.h winsock2.h ws2tcpip.h])-AC_CHECK_HEADERS([arpa/inet.h netdb.h netinet/in.h netinet/tcp.h sys/socket.h sys/uio.h sys/un.h linux/can.h linux/tcp.h])-AC_CHECK_HEADERS([net/if.h])--AC_CHECK_FUNCS([readlink symlink if_nametoindex])--dnl ** check what fields struct msghdr contains-AC_CHECK_MEMBERS([struct msghdr.msg_control, struct msghdr.msg_accrights], [], [], [#if HAVE_SYS_TYPES_H-# include <sys/types.h>-#endif-#if HAVE_SYS_SOCKET_H-# include <sys/socket.h>-#endif-#if HAVE_SYS_UIO_H-# include <sys/uio.h>-#endif])--dnl ** check if struct sockaddr contains sa_len-AC_CHECK_MEMBERS([struct sockaddr.sa_len], [], [], [#if HAVE_SYS_TYPES_H-# include <sys/types.h>-#endif-#if HAVE_SYS_SOCKET_H-# include <sys/socket.h>-#endif])--dnl ---------------------------------------------------dnl * test for in_addr_t-dnl ---------------------------------------------------AC_MSG_CHECKING(for in_addr_t in netinet/in.h)-AC_EGREP_HEADER(in_addr_t, netinet/in.h,- [ AC_DEFINE([HAVE_IN_ADDR_T], [1], [Define to 1 if in_addr_t is available.]) AC_MSG_RESULT(yes) ],- AC_MSG_RESULT(no))--dnl ---------------------------------------------------dnl * test for SO_PEERCRED and struct ucred-dnl ---------------------------------------------------AC_MSG_CHECKING(for SO_PEERCRED and struct ucred in sys/socket.h)-AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <sys/types.h>-#include <sys/socket.h>-#ifndef SO_PEERCRED-# error no SO_PEERCRED-#endif-struct ucred u;]])],ac_cv_ucred=yes,ac_cv_ucred=no)-if test "x$ac_cv_ucred" = xno; then-    old_CFLAGS="$CFLAGS"-    CFLAGS="-D_GNU_SOURCE $CFLAGS"-    AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <sys/types.h>-#include <sys/socket.h>-#ifndef SO_PEERCRED-# error no SO_PEERCRED-#endif-struct ucred u;]])],ac_cv_ucred=yes,ac_cv_ucred=no)-    if test "x$ac_cv_ucred" = xyes; then-        EXTRA_CPPFLAGS=-D_GNU_SOURCE-    fi-else-    old_CFLAGS="$CFLAGS"-fi-if test "x$ac_cv_ucred" = xno; then-    CFLAGS="$old_CFLAGS"-    AC_MSG_RESULT(no)-else-    AC_DEFINE([HAVE_STRUCT_UCRED], [1], [Define to 1 if you have both SO_PEERCRED and struct ucred.])-    AC_MSG_RESULT(yes)-fi--dnl ---------------------------------------------------dnl * test for GETPEEREID(3)-dnl ---------------------------------------------------AC_MSG_CHECKING(for getpeereid in unistd.h)-AC_CHECK_FUNC( getpeereid, AC_DEFINE([HAVE_GETPEEREID], [1], [Define to 1 if you have getpeereid.] ))--dnl ---------------------------------------------------dnl * check for Windows networking libraries-dnl ---------------------------------------------------AC_CHECK_LIB(ws2_32, _head_libws2_32_a)--dnl ---------------------------------------------------dnl * test for getaddrinfo as proxy for IPv6 support-dnl ---------------------------------------------------AC_MSG_CHECKING(for getaddrinfo)-dnl Can't use AC_CHECK_FUNC here, because it doesn't do the right-dnl thing on Windows.-AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[$ac_includes_default-int testme(){ getaddrinfo; }]])],[AC_DEFINE([HAVE_GETADDRINFO], [1], [Define to 1 if you have the `getaddrinfo' function.]) ac_have_getaddrinfo=yes; AC_MSG_RESULT(yes)],[AC_MSG_RESULT(no)])+AC_CHECK_HEADERS([limits.h stdlib.h unistd.h sys/types.h fcntl.h])+AC_CHECK_HEADERS([sys/uio.h sys/socket.h netinet/in.h netinet/tcp.h])+AC_CHECK_HEADERS([sys/un.h arpa/inet.h netdb.h])+AC_CHECK_HEADERS([net/if.h netioapi.h]) -dnl Under mingw, we may need to set WINVER to 0x0501 to expose getaddrinfo.-if test "x$ac_have_getaddrinfo" = x; then-  old_CFLAGS="$CFLAGS"-  if test "z$ac_cv_lib_ws2_32__head_libws2_32_a" = zyes; then-    CFLAGS="-DWINVER=0x0501 $CFLAGS"-    AC_MSG_CHECKING(for getaddrinfo if WINVER is 0x0501)-    AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[$ac_includes_default-    int testme(){ getaddrinfo; }]])],[AC_DEFINE([HAVE_GETADDRINFO], [1], [Define to 1 if you have the `getaddrinfo' function.]) AC_DEFINE([NEED_WINVER_XP], [1], [Define to 1 if the `getaddrinfo' function needs WINVER set.]) EXTRA_CPPFLAGS="-DWINVER=0x0501 $EXTRA_CPPFLAGS"; AC_MSG_RESULT(yes)],[CFLAGS="$old_CFLAGS"; AC_MSG_RESULT(no)])-  fi-fi+AC_CHECK_TYPES([struct ucred]) -dnl Missing under mingw, sigh.-AC_CHECK_FUNCS(gai_strerror)+AC_CHECK_FUNCS([gai_strerror gethostent accept4])+AC_CHECK_FUNCS([getpeereid]) -dnl --------------------------------------------------------dnl * test for AI_* flags that not all implementations have-dnl ------------------------------------------------------- AC_CHECK_DECLS([AI_ADDRCONFIG, AI_ALL, AI_NUMERICSERV, AI_V4MAPPED])--dnl --------------------------------------------------------dnl * test for IPV6_V6ONLY flags that not all implementations have-dnl ------------------------------------------------------- AC_CHECK_DECLS([IPV6_V6ONLY])--dnl --------------------------------------------------------dnl * test for IPPROTO_* macros/constants-dnl ------------------------------------------------------- AC_CHECK_DECLS([IPPROTO_IP, IPPROTO_TCP, IPPROTO_IPV6])--dnl ---------------------------------------------------dnl * test for Linux sendfile(2)-dnl ---------------------------------------------------AC_MSG_CHECKING(for sendfile in sys/sendfile.h)-AC_EGREP_HEADER(sendfile, sys/sendfile.h,- [ AC_DEFINE([HAVE_LINUX_SENDFILE], [1], [Define to 1 if you have a Linux sendfile(2) implementation.]) AC_MSG_RESULT(yes) ],- AC_MSG_RESULT(no))--dnl ---------------------------------------------------dnl * test for BSD sendfile(2)-dnl ---------------------------------------------------AC_MSG_CHECKING(for sendfile in sys/socket.h)-AC_EGREP_HEADER(sendfile, sys/socket.h,- [ AC_DEFINE([HAVE_BSD_SENDFILE], [1], [Define to 1 if you have a BSDish sendfile(2) implementation.]) AC_MSG_RESULT(yes) ],- AC_MSG_RESULT(no))--AC_CHECK_FUNCS(gethostent)--AC_CHECK_FUNCS(accept4)+AC_CHECK_DECLS([SO_PEERCRED]) -case "$host" in-*-mingw* | *-msys*)-	EXTRA_SRCS="cbits/initWinSock.c, cbits/winSockErr.c, cbits/asyncAccept.c"-	EXTRA_LIBS=ws2_32-	;;-*-solaris2*)-	EXTRA_SRCS="cbits/ancilData.c"-	EXTRA_LIBS="nsl, socket"-	;;-*)-	EXTRA_SRCS="cbits/ancilData.c"-	EXTRA_LIBS=-	;;-esac-AC_SUBST([EXTRA_CPPFLAGS])-AC_SUBST([EXTRA_LIBS])-AC_SUBST([EXTRA_SRCS])+AC_CHECK_MEMBERS([struct msghdr.msg_control, struct msghdr.msg_accrights])+AC_CHECK_MEMBERS([struct sockaddr.sa_len]) -AC_CONFIG_FILES([network.buildinfo])+dnl This is a necessary hack+AC_MSG_NOTICE([creating ./network.buildinfo])+echo "install-includes: HsNetworkConfig.h" > network.buildinfo  AC_OUTPUT
examples/EchoClient.hs view
@@ -4,7 +4,7 @@  import qualified Control.Exception as E import qualified Data.ByteString.Char8 as C-import Network.Socket hiding (recv)+import Network.Socket import Network.Socket.ByteString (recv, sendAll)  main :: IO ()
examples/EchoServer.hs view
@@ -5,7 +5,7 @@ import qualified Control.Exception as E import Control.Monad (unless, forever, void) import qualified Data.ByteString as S-import Network.Socket hiding (recv)+import Network.Socket import Network.Socket.ByteString (recv, sendAll)  main :: IO ()@@ -25,7 +25,7 @@         setSocketOption sock ReuseAddr 1         -- If the prefork technique is not used,         -- set CloseOnExec for the security reasons.-        let fd = fdSocket sock+        fd <- fdSocket sock         setCloseOnExecIfNeeded fd         bind sock (addrAddress addr)         listen sock 10
include/HsNet.h view
@@ -9,10 +9,6 @@  #include "HsNetDef.h" -#ifdef NEED_WINVER-# define WINVER 0x0501-#endif- #ifndef INLINE # if defined(_MSC_VER) #  define INLINE extern __inline@@ -23,29 +19,13 @@ # endif #endif -#ifdef HAVE_GETADDRINFO-# define IPV6_SOCKET_SUPPORT 1-#else-# undef IPV6_SOCKET_SUPPORT-#endif--#if defined(HAVE_WINSOCK2_H)-#include <winsock2.h>-# ifdef HAVE_WS2TCPIP_H-#  include <ws2tcpip.h>-// fix for MingW not defining IPV6_V6ONLY-#  define IPV6_V6ONLY 27-# endif--extern int   initWinSock ();-extern const char* getWSErrorDescr(int err);-extern void* newAcceptParams(int sock,-			     int sz,-			     void* sockaddr);-extern int   acceptNewSock(void* d);-extern int   acceptDoProc(void* param);+#define _GNU_SOURCE 1 /* for struct ucred on Linux */ -#else+#ifdef _WIN32+# include <winsock2.h>+# include <ws2tcpip.h>+# define IPV6_V6ONLY 27+#endif  #ifdef HAVE_LIMITS_H # include <limits.h>@@ -68,14 +48,12 @@ #ifdef HAVE_SYS_SOCKET_H # include <sys/socket.h> #endif-#ifdef HAVE_LINUX_TCP_H-# include <linux/tcp.h>-#elif HAVE_NETINET_TCP_H-# include <netinet/tcp.h>-#endif #ifdef HAVE_NETINET_IN_H # include <netinet/in.h> #endif+#ifdef HAVE_NETINET_TCP_H+# include <netinet/tcp.h>+#endif #ifdef HAVE_SYS_UN_H # include <sys/un.h> #endif@@ -85,34 +63,32 @@ #ifdef HAVE_NETDB_H #include <netdb.h> #endif-#ifdef HAVE_LINUX_CAN_H-# include <linux/can.h>-# define CAN_SOCKET_SUPPORT 1-#endif-#ifdef HAVE_NET_IF+#ifdef HAVE_NET_IF_H # include <net/if.h> #endif--#ifdef HAVE_BSD_SENDFILE-#include <sys/uio.h>-#endif-#ifdef HAVE_LINUX_SENDFILE-#if !defined(__USE_FILE_OFFSET64)-#include <sys/sendfile.h>-#endif+#ifdef HAVE_NETIOAPI_H+# include <netioapi.h> #endif +#ifdef _WIN32+extern int   initWinSock ();+extern const char* getWSErrorDescr(int err);+extern void* newAcceptParams(int sock,+			     int sz,+			     void* sockaddr);+extern int   acceptNewSock(void* d);+extern int   acceptDoProc(void* param);+#else  /* _WIN32 */ extern int sendFd(int sock, int outfd);  extern int recvFd(int sock);--#endif /* HAVE_WINSOCK2_H */+#endif /* _WIN32 */  INLINE char * hsnet_inet_ntoa(-#if defined(HAVE_WINSOCK2_H)+#if defined(_WIN32)              u_long addr #elif defined(HAVE_IN_ADDR_T)              in_addr_t addr@@ -128,10 +104,9 @@     return inet_ntoa(a); } -#ifdef HAVE_GETADDRINFO INLINE int hsnet_getnameinfo(const struct sockaddr* a,socklen_t b, char* c,-# if defined(HAVE_WINSOCK2_H)+# if defined(_WIN32)                   DWORD d, char* e, DWORD f, int g) # else                   socklen_t d, char* e, socklen_t f, int g)@@ -152,13 +127,12 @@ {     freeaddrinfo(ai); }-#endif -#if !defined(IOV_MAX)+#ifndef IOV_MAX # define IOV_MAX 1024 #endif -#if !defined(SOCK_NONBLOCK) // Missing define in Bionic libc (Android)+#ifndef SOCK_NONBLOCK // Missing define in Bionic libc (Android) # define SOCK_NONBLOCK O_NONBLOCK #endif 
include/HsNetDef.h view
@@ -10,14 +10,22 @@ #undef PACKAGE_TARNAME #undef PACKAGE_VERSION -#if defined(HAVE_WINSOCK2_H)-# define WITH_WINSOCK  1-#endif- #if !defined(mingw32_HOST_OS) && !defined(_WIN32) # define DOMAIN_SOCKET_SUPPORT 1 #endif +#if defined(HAVE_STRUCT_UCRED) && HAVE_DECL_SO_PEERCRED+# define HAVE_STRUCT_UCRED_SO_PEERCRED 1+#else+# undef HAVE_STRUCT_UCRED_SO_PEERCRED+#endif++#ifdef HAVE_ACCEPT4+# define HAVE_ADVANCED_SOCKET_FLAGS 1+#else+# undef HAVE_ADVANCED_SOCKET_FLAGS+#endif+ /* stdcall is for Windows 32.    Haskell FFI does not have a keyword for Windows 64.    If ccall/stdcall is specified on Windows 64,@@ -36,6 +44,7 @@ #else # define CALLCONV ccall #endif+ #if defined(mingw32_HOST_OS) # define SAFE_ON_WIN safe #else
include/HsNetworkConfig.h.in view
@@ -6,9 +6,6 @@ /* Define to 1 if you have the <arpa/inet.h> header file. */ #undef HAVE_ARPA_INET_H -/* Define to 1 if you have a BSDish sendfile(2) implementation. */-#undef HAVE_BSD_SENDFILE- /* Define to 1 if you have the declaration of `AI_ADDRCONFIG', and to 0 if you    don't. */ #undef HAVE_DECL_AI_ADDRCONFIG@@ -41,45 +38,28 @@    don't. */ #undef HAVE_DECL_IPV6_V6ONLY +/* Define to 1 if you have the declaration of `SO_PEERCRED', and to 0 if you+   don't. */+#undef HAVE_DECL_SO_PEERCRED+ /* Define to 1 if you have the <fcntl.h> header file. */ #undef HAVE_FCNTL_H  /* Define to 1 if you have the `gai_strerror' function. */ #undef HAVE_GAI_STRERROR -/* Define to 1 if you have the `getaddrinfo' function. */-#undef HAVE_GETADDRINFO- /* Define to 1 if you have the `gethostent' function. */ #undef HAVE_GETHOSTENT -/* Define to 1 if you have getpeereid. */+/* Define to 1 if you have the `getpeereid' function. */ #undef HAVE_GETPEEREID -/* Define to 1 if you have the `if_nametoindex' function. */-#undef HAVE_IF_NAMETOINDEX- /* Define to 1 if you have the <inttypes.h> header file. */ #undef HAVE_INTTYPES_H -/* Define to 1 if in_addr_t is available. */-#undef HAVE_IN_ADDR_T--/* Define to 1 if you have the `ws2_32' library (-lws2_32). */-#undef HAVE_LIBWS2_32- /* Define to 1 if you have the <limits.h> header file. */ #undef HAVE_LIMITS_H -/* Define to 1 if you have the <linux/can.h> header file. */-#undef HAVE_LINUX_CAN_H--/* Define to 1 if you have a Linux sendfile(2) implementation. */-#undef HAVE_LINUX_SENDFILE--/* Define to 1 if you have the <linux/tcp.h> header file. */-#undef HAVE_LINUX_TCP_H- /* Define to 1 if you have the <memory.h> header file. */ #undef HAVE_MEMORY_H @@ -92,12 +72,12 @@ /* Define to 1 if you have the <netinet/tcp.h> header file. */ #undef HAVE_NETINET_TCP_H +/* Define to 1 if you have the <netioapi.h> header file. */+#undef HAVE_NETIOAPI_H+ /* Define to 1 if you have the <net/if.h> header file. */ #undef HAVE_NET_IF_H -/* Define to 1 if you have the `readlink' function. */-#undef HAVE_READLINK- /* Define to 1 if you have the <stdint.h> header file. */ #undef HAVE_STDINT_H @@ -119,12 +99,9 @@ /* Define to 1 if `sa_len' is a member of `struct sockaddr'. */ #undef HAVE_STRUCT_SOCKADDR_SA_LEN -/* Define to 1 if you have both SO_PEERCRED and struct ucred. */+/* Define to 1 if the system has the type `struct ucred'. */ #undef HAVE_STRUCT_UCRED -/* Define to 1 if you have the `symlink' function. */-#undef HAVE_SYMLINK- /* Define to 1 if you have the <sys/socket.h> header file. */ #undef HAVE_SYS_SOCKET_H @@ -142,15 +119,6 @@  /* Define to 1 if you have the <unistd.h> header file. */ #undef HAVE_UNISTD_H--/* Define to 1 if you have the <winsock2.h> header file. */-#undef HAVE_WINSOCK2_H--/* Define to 1 if you have the <ws2tcpip.h> header file. */-#undef HAVE_WS2TCPIP_H--/* Define to 1 if the `getaddrinfo' function needs WINVER set. */-#undef NEED_WINVER_XP  /* Define to the address where bug reports for this package should be sent. */ #undef PACKAGE_BUGREPORT
− network.buildinfo.in
@@ -1,7 +0,0 @@-ghc-options: @EXTRA_CPPFLAGS@-ghc-prof-options: @EXTRA_CPPFLAGS@-ld-options: @LDFLAGS@-cc-options: @EXTRA_CPPFLAGS@-c-sources: @EXTRA_SRCS@-extra-libraries: @EXTRA_LIBS@-install-includes: HsNetworkConfig.h
network.cabal view
@@ -1,5 +1,6 @@+cabal-version:  1.18 name:           network-version:        2.8.0.1+version:        3.0.0.0 license:        BSD3 license-file:   LICENSE maintainer:     Kazu Yamamoto, Evan Borden@@ -7,23 +8,35 @@ description:   This package provides a low-level networking interface.   .-  In network-2.6 the @Network.URI@ module was split off into its own-  package, network-uri-2.6. If you're using the @Network.URI@ module-  you can automatically get it from the right package by adding this-  to your .cabal file:+  === High-Level Packages+  Other packages provide higher level interfaces:   .+  * connection+  * hookup+  * network-simple+  .+  === Related Packages+  ==== @network-bsd@+  In @network-3.0.0.0@ the @Network.BSD@ module was split off into its own+  package, @network-bsd-3.0.0.0@.+  .+  ==== @network-uri@+  In @network-2.6@ the @Network.URI@ module was split off into its own package,+  @network-uri-2.6@. If you're using the @Network.URI@ module you can+  automatically get it from the right package by adding this to your @.cabal@+  file:+  .   > library   >   build-depends: network-uri-flag category:       Network build-type:     Configure-cabal-version:  >=1.8 extra-tmp-files:   config.log config.status autom4te.cache network.buildinfo   include/HsNetworkConfig.h extra-source-files:   README.md CHANGELOG.md   examples/*.hs tests/*.hs config.guess config.sub install-sh-  configure.ac configure network.buildinfo.in+  configure.ac configure   include/HsNetworkConfig.h.in include/HsNet.h include/HsNetDef.h   -- C sources only used on some systems   cbits/ancilData.c cbits/asyncAccept.c cbits/initWinSock.c@@ -34,53 +47,76 @@              , GHC == 7.10.3              , GHC == 8.0.2              , GHC == 8.2.2-             , GHC == 8.4.3+             , GHC == 8.4.4+             , GHC == 8.6.2  library+  default-language: Haskell2010   exposed-modules:-    Network-    Network.BSD     Network.Socket+    Network.Socket.Address     Network.Socket.ByteString     Network.Socket.ByteString.Lazy     Network.Socket.Internal   other-modules:+    Network.Socket.Buffer     Network.Socket.ByteString.Internal+    Network.Socket.ByteString.IO+    Network.Socket.Cbits+    Network.Socket.Fcntl+    Network.Socket.Handle+    Network.Socket.Imports+    Network.Socket.If+    Network.Socket.Info+    Network.Socket.Name+    Network.Socket.Options+    Network.Socket.Shutdown+    Network.Socket.SockAddr+    Network.Socket.Syscall     Network.Socket.Types--  if !os(windows)-    other-modules:-      Network.Socket.ByteString.IOVec-      Network.Socket.ByteString.Lazy.Posix-      Network.Socket.ByteString.MsgHdr-  if os(windows)-    other-modules:-      Network.Socket.ByteString.Lazy.Windows+    Network.Socket.Unix    build-depends:     base >= 4.7 && < 5,-    bytestring == 0.10.*--  if !os(windows)-    build-depends:-      unix >= 2+    bytestring == 0.10.*,+    deepseq -  extensions:-    CPP, DeriveDataTypeable, ForeignFunctionInterface, TypeSynonymInstances   include-dirs: include   includes: HsNet.h HsNetDef.h   install-includes: HsNet.h HsNetDef.h   c-sources: cbits/HsNet.c   ghc-options: -Wall -fwarn-tabs+  build-tools: hsc2hs ++  -- Add some platform specific stuff+  if !os(windows)+    other-modules:+      Network.Socket.ByteString.IOVec+      Network.Socket.ByteString.Lazy.Posix+      Network.Socket.ByteString.MsgHdr+    build-depends:+      unix >= 2+    c-sources: cbits/ancilData.c++  if os(solaris)+    extra-libraries: nsl, socket++  if os(windows)+    other-modules:+      Network.Socket.ByteString.Lazy.Windows+    c-sources: cbits/initWinSock.c, cbits/winSockErr.c, cbits/asyncAccept.c+    extra-libraries: ws2_32+    -- See https://github.com/haskell/network/pull/362+    if impl(ghc >= 7.10)+      cpp-options: -D_WIN32_WINNT=0x0600+ test-suite spec+  default-language: Haskell2010   hs-source-dirs: tests   main-is: Spec.hs-  other-modules:-    Network.Test.Common-    Network.SocketSpec-    Network.Socket.ByteStringSpec-    Network.Socket.ByteString.LazySpec+  other-modules: RegressionSpec+                 SimpleSpec   type: exitcode-stdio-1.0   ghc-options: -Wall -threaded   -- NB: make sure to versions of hspec and hspec-discover@@ -95,14 +131,17 @@     network,     hspec >= 2.6 -test-suite doctest+test-suite doctests+  buildable: False+  default-language: Haskell2010   hs-source-dirs: tests   main-is: doctests.hs   type: exitcode-stdio-1.0    build-depends:     base >= 4.7 && < 5,-    doctest >= 0.10.1+    doctest >= 0.10.1,+    network    ghc-options: -Wall 
− tests/Network/Socket/ByteString/LazySpec.hs
@@ -1,54 +0,0 @@-{-# LANGUAGE CPP #-}-{-# LANGUAGE OverloadedStrings #-}--module Network.Socket.ByteString.LazySpec (main, spec) where--import Prelude hiding (getContents)--import qualified Data.ByteString.Lazy as L-import Network.Socket hiding (recv, recvFrom, send, sendTo)-import Network.Socket.ByteString.Lazy-import Network.Test.Common-import Control.Monad--import Test.Hspec--main :: IO ()-main = hspec spec--spec :: Spec-spec = do-    describe "send" $ do-        it "works well" $ do-            let server sock = recv sock 1024 `shouldReturn` lazyTestMsg-                client sock = send sock lazyTestMsg-            tcpTest client server--    describe "sendAll" $ do-        it "works well" $ do-            let server sock = recv sock 1024 `shouldReturn` lazyTestMsg-                client sock = sendAll sock lazyTestMsg-            tcpTest client server--    describe "getContents" $ do-        it "works well" $ do-            let server sock = getContents sock `shouldReturn` lazyTestMsg-                client sock = do-                    void $ send sock lazyTestMsg-                    shutdown sock ShutdownSend-            tcpTest client server--    describe "recv" $ do-        it "works well" $ do-            let server sock = recv sock 1024 `shouldReturn` lazyTestMsg-                client sock = send sock lazyTestMsg-            tcpTest client server--        it "can treat overflow" $ do-            let server sock = do-                    seg1 <- recv sock (L.length lazyTestMsg - 3)-                    seg2 <- recv sock 1024-                    let msg = L.append seg1 seg2-                    msg `shouldBe` lazyTestMsg-                client sock = send sock lazyTestMsg-            tcpTest client server
− tests/Network/Socket/ByteStringSpec.hs
@@ -1,109 +0,0 @@-{-# LANGUAGE OverloadedStrings #-}--module Network.Socket.ByteStringSpec (main, spec) where--import qualified Data.ByteString as S-import qualified Data.ByteString.Char8 as C-import Network.Socket hiding (recv, recvFrom, send, sendTo)-import Network.Socket.ByteString-import Network.Test.Common--import Test.Hspec--main :: IO ()-main = hspec spec--spec :: Spec-spec = do-    describe "send" $ do-        it "works well" $ do-            let server sock = recv sock 1024 `shouldReturn` testMsg-                client sock = send sock testMsg-            tcpTest client server--        it "checks -1 correctly on Windows" $ do-            sock <- socket AF_INET Stream defaultProtocol-            send sock "hello world" `shouldThrow` anyException--    describe "sendAll" $ do-        it "works well" $ do-            let server sock = recv sock 1024 `shouldReturn` testMsg-                client sock = sendAll sock testMsg-            tcpTest client server--    describe "sendTo" $ do-        it "works well" $ do-            let server sock = recv sock 1024 `shouldReturn` testMsg-                client sock serverPort = do-                    let hints = defaultHints { addrFlags = [AI_NUMERICHOST], addrSocketType = Datagram }-                    addr:_ <- getAddrInfo (Just hints) (Just serverAddr) (Just $ show serverPort)-                    sendTo sock testMsg $ addrAddress addr-            udpTest client server--    describe "sendAllTo" $ do-        it "works well" $ do-            let server sock = recv sock 1024 `shouldReturn` testMsg-                client sock serverPort = do-                    let hints = defaultHints { addrFlags = [AI_NUMERICHOST], addrSocketType = Datagram }-                    addr:_ <- getAddrInfo (Just hints) (Just serverAddr) (Just $ show serverPort)-                    sendAllTo sock testMsg $ addrAddress addr-            udpTest client server--    describe "sendMany" $ do-        it "works well" $ do-            let server sock = recv sock 1024 `shouldReturn` S.append seg1 seg2-                client sock = sendMany sock [seg1, seg2]--                seg1 = C.pack "This is a "-                seg2 = C.pack "test message."-            tcpTest client server--    describe "sendManyTo" $ do-        it "works well" $ do-            let server sock = recv sock 1024 `shouldReturn` S.append seg1 seg2-                client sock serverPort = do-                    let hints = defaultHints { addrFlags = [AI_NUMERICHOST], addrSocketType = Datagram }-                    addr:_ <- getAddrInfo (Just hints) (Just serverAddr) (Just $ show serverPort)-                    sendManyTo sock [seg1, seg2] $ addrAddress addr--                seg1 = C.pack "This is a "-                seg2 = C.pack "test message."-            udpTest client server--    describe "recv" $ do-        it "works well" $ do-            let server sock = recv sock 1024 `shouldReturn` testMsg-                client sock = send sock testMsg-            tcpTest client server--        it "can treat overflow" $ do-            let server sock = do-                    seg1 <- recv sock (S.length testMsg - 3)-                    seg2 <- recv sock 1024-                    let msg = S.append seg1 seg2-                    msg `shouldBe` testMsg-                client sock = send sock testMsg-            tcpTest client server--        it "checks -1 correctly on Windows" $ do-            sock <- socket AF_INET Stream defaultProtocol-            recv sock 1024 `shouldThrow` anyException--    describe "recvFrom" $ do-        it "works well" $ do-            let server sock = do-                    (msg, _) <- recvFrom sock 1024-                    testMsg `shouldBe` msg-                client sock = do-                    addr <- getPeerName sock-                    sendTo sock testMsg addr-            tcpTest client server--        it "can treat overflow" $ do-            let server sock = do-                    (seg1, _) <- recvFrom sock (S.length testMsg - 3)-                    (seg2, _) <- recvFrom sock 1024-                    let msg = S.append seg1 seg2-                    testMsg `shouldBe` msg-                client sock = send sock testMsg-            tcpTest client server
− tests/Network/SocketSpec.hs
@@ -1,126 +0,0 @@-{-# LANGUAGE CPP #-}-{-# LANGUAGE OverloadedStrings #-}--module Network.SocketSpec (main, spec) where--import Control.Concurrent.MVar (readMVar)-import Control.Monad-import Network.Socket hiding (recv, send)-import Network.Socket.ByteString-import Network.Test.Common--import Test.Hspec--main :: IO ()-main = hspec spec--spec :: Spec-spec = do-    describe "connect" $ do-        let-          hints = defaultHints { addrSocketType = Stream }-          connect' serverPort = do-              addr:_ <- getAddrInfo (Just hints) (Just serverAddr) (Just $ show serverPort)-              sock <- socket (addrFamily addr) (addrSocketType addr) (addrProtocol addr)-              connect sock (addrAddress addr)-              return sock--        it "fails to connect and throws an IOException" $ do-            connect' (8080 :: Int) `shouldThrow` anyIOException--        it "successfully connects to a socket with no exception" $ do-            tcpTestUsingClient return return $ readMVar >=> connect'--    describe "UserTimeout" $ do-        it "can be set" $ do-            when (isSupportedSocketOption UserTimeout) $ do-              sock <- socket AF_INET Stream defaultProtocol-              setSocketOption sock UserTimeout 1000-              getSocketOption sock UserTimeout `shouldReturn` 1000-              setSocketOption sock UserTimeout 2000-              getSocketOption sock UserTimeout `shouldReturn` 2000-              close sock--    -- On various BSD systems the peer credentials are exchanged during-    -- connect(), and this does not happen with `socketpair()`.  Therefore,-    -- we must actually set up a listener and connect, rather than use a-    -- socketpair().-    ---    describe "getPeerCredential" $ do-        it "can return something" $ do-            when isUnixDomainSocketAvailable $ do-                -- It would be useful to check that we did not get garbage-                -- back, but rather the actual uid of the test program.  For-                -- that we'd need System.Posix.User, but that is not available-                -- under Windows.  For now, accept the risk that we did not get-                -- the right answer.-                ---                let client sock = do-                        (_, uid, _) <- getPeerCredential sock-                        uid `shouldNotBe` Nothing-                    server (sock, _) = do-                        (_, uid, _) <- getPeerCredential sock-                        uid `shouldNotBe` Nothing-                unixTest client server-        {- The below test fails on many *BSD systems, because the getsockopt()-           call that underlies getpeereid() does not have the same meaning for-           all address families, but the C-library was not checking that the-           provided sock is an AF_UNIX socket.  This will fixed some day, but-           we should not fail on those systems in the mean-time.  The upstream-           C-library fix is to call getsockname() and check the address family-           before calling `getpeereid()`.  We could duplicate that in our own-           code, and then this test would work on those platforms that have-           `getpeereid()` and not the SO_PEERCRED socket option.--        it "return nothing for non-UNIX-domain socket" $ do-            when isUnixDomainSocketAvailable $ do-                s <- socket AF_INET Stream defaultProtocol-                cred1 <- getPeerCredential s-                cred1 `shouldBe` (Nothing,Nothing,Nothing)-        -}--    describe "getAddrInfo" $ do-        it "works for IPv4 address" $ do-            let hints = defaultHints { addrFlags = [AI_NUMERICHOST, AI_ADDRCONFIG] }-            AddrInfo{addrAddress = (SockAddrInet _ hostAddr)}:_ <--                getAddrInfo (Just hints) (Just "127.128.129.130") Nothing-            hostAddressToTuple hostAddr `shouldBe` (0x7f, 0x80, 0x81, 0x82)--#if defined(IPV6_SOCKET_SUPPORT)-        it "works for IPv6 address" $ do-            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-            hostAddress6ToTuple hostAddr-                `shouldBe` (0x2001, 0x0db8, 0x85a3, 0x0000, 0x0000, 0x8a2e, 0x0370, 0x7334)-#endif--        it "does not cause segfault on macOS 10.8.2 due to AI_NUMERICSERV" $ do-            let hints = defaultHints { addrFlags = [AI_NUMERICSERV] }-            void $ getAddrInfo (Just hints) (Just "localhost") Nothing--    describe "unix sockets" $ do-        it "basic unix sockets end-to-end" $ do-            when isUnixDomainSocketAvailable $ do-                let client sock = send sock testMsg-                    server (sock, addr) = do-                      recv sock 1024 `shouldReturn` testMsg-                      addr `shouldBe` (SockAddrUnix "")-                unixTest client server-#ifdef linux_HOST_OS-        it "can end-to-end with an abstract socket" $ do-            when isUnixDomainSocketAvailable $ do-                let-                    abstractAddress = toEnum 0:"/haskell/network/abstract"-                    clientAct sock = send sock testMsg-                    server (sock, addr) = do-                      recv sock 1024 `shouldReturn` testMsg-                      addr `shouldBe` (SockAddrUnix "")-                unixTestWith abstractAddress (const $ return ()) clientAct server-        it "safely throws an exception" $ do-            when isUnixDomainSocketAvailable $ do-                let abstractAddress = toEnum 0:"/haskell/network/abstract-longlonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglong"-                sock <- socket AF_UNIX Stream defaultProtocol-                bind sock (SockAddrUnix abstractAddress) `shouldThrow` anyErrorCall-#endif
− tests/Network/Test/Common.hs
@@ -1,200 +0,0 @@-{-# LANGUAGE CPP #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE ScopedTypeVariables #-}--module Network.Test.Common-  ( serverAddr-  , testMsg-  , lazyTestMsg-  , tcpTest-  , tcpTestUsingClient-  , unixTest-  , unixTestWith-  , udpTest-  ) where--import Control.Concurrent (ThreadId, forkIO, myThreadId)-import Control.Concurrent.MVar (MVar, newEmptyMVar, putMVar, takeMVar, readMVar)-import qualified Control.Exception as E-import Control.Monad-import Data.ByteString (ByteString)-import Network.Socket-import System.Directory-import qualified Data.ByteString.Lazy as L-import System.Timeout (timeout)--import Test.Hspec--serverAddr :: String-serverAddr = "127.0.0.1"--testMsg :: ByteString-testMsg = "This is a test message."--lazyTestMsg :: L.ByteString-lazyTestMsg = L.fromStrict "This is a test message."--unixAddr :: String-unixAddr = "/tmp/network-test"---- | Establish a connection between client and server and then run--- 'clientAct' and 'serverAct', in different threads.  Both actions--- get passed a connected 'Socket', used for communicating between--- client and server.  'unixTest' makes sure that the 'Socket' is--- closed after the actions have run.-unixTest :: (Socket -> IO a) -> ((Socket, SockAddr) -> IO b) -> IO ()-unixTest = unixTestWith unixAddr unlink-  where-    unlink file = do-        exist <- doesFileExist file-        when exist $ removeFile file--unixTestWith-    :: String -- ^ address-    -> (String -> IO ()) -- ^ clean up action-    -> (Socket -> IO a) -- ^ client action-    -> ((Socket, SockAddr) -> IO b) -- ^ server action-    -> IO ()-unixTestWith address cleanupAct clientAct serverAct =-    test clientSetup clientAct serverSetup server-  where-    clientSetup = do-        sock <- socket AF_UNIX Stream defaultProtocol-        connect sock (SockAddrUnix address)-        return sock--    serverSetup = do-        sock <- socket AF_UNIX Stream defaultProtocol-        cleanupAct address -- just in case-        bind sock (SockAddrUnix address)-        listen sock 1-        return sock--    server sock = E.bracket (accept sock) (killClientSock . fst) serverAct--    killClientSock sock = do-        shutdown sock ShutdownBoth-        close sock-        cleanupAct address---- | Establish a connection between client and server and then run--- 'clientAct' and 'serverAct', in different threads.  Both actions--- get passed a connected 'Socket', used for communicating between--- client and server.  'tcpTest' makes sure that the 'Socket' is--- closed after the actions have run.-tcpTest :: (Socket -> IO a) -> (Socket -> IO b) -> IO ()-tcpTest clientAct serverAct =-    tcpTestUsingClient serverAct clientAct clientSetup-  where-    clientSetup portVar = do-        let hints = defaultHints { addrSocketType = Stream }-        serverPort <- readMVar portVar-        addr:_ <- getAddrInfo (Just hints) (Just serverAddr) (Just $ show serverPort)-        sock <- socket (addrFamily addr) (addrSocketType addr) (addrProtocol addr)-#if !defined(mingw32_HOST_OS)-        let fd = fdSocket sock-        getNonBlock fd `shouldReturn` True-        getCloseOnExec fd `shouldReturn` False-#endif-        connect sock $ addrAddress addr-        return sock--tcpTestUsingClient-    :: (Socket -> IO a) -> (Socket -> IO b) -> (MVar PortNumber -> IO Socket) -> IO ()-tcpTestUsingClient serverAct clientAct clientSetup = do-    portVar <- newEmptyMVar-    test (clientSetup portVar) clientAct (serverSetup portVar) server-  where-    serverSetup portVar = do-        let hints = defaultHints {-                addrFlags = [AI_PASSIVE]-              , addrSocketType = Stream-              }-        addr:_ <- getAddrInfo (Just hints) (Just serverAddr) Nothing-        sock <- socket (addrFamily addr) (addrSocketType addr) (addrProtocol addr)-        let fd = fdSocket sock-#if !defined(mingw32_HOST_OS)-        getNonBlock fd `shouldReturn` True-        getCloseOnExec fd `shouldReturn` False-#endif-        setSocketOption sock ReuseAddr 1-        setCloseOnExecIfNeeded fd-#if !defined(mingw32_HOST_OS)-        getCloseOnExec fd `shouldReturn` True-#endif-        bind sock $ addrAddress addr-        listen sock 1-        serverPort <- socketPort sock-        putMVar portVar serverPort-        return sock--    server sock = do-        (clientSock, _) <- accept sock-#if !defined(mingw32_HOST_OS)-        let fd = fdSocket clientSock-        getNonBlock fd `shouldReturn` True-        getCloseOnExec fd `shouldReturn` True-#endif-        _ <- serverAct clientSock-        close clientSock---- | Create an unconnected 'Socket' for sending UDP and receiving--- datagrams and then run 'clientAct' and 'serverAct'.-udpTest :: (Socket -> PortNumber -> IO a) -> (Socket -> IO b) -> IO ()-udpTest clientAct serverAct = do-    portVar <- newEmptyMVar-    test clientSetup (client portVar) (serverSetup portVar) serverAct-  where-    clientSetup = socket AF_INET Datagram defaultProtocol--    client portVar sock = do-        serverPort <- readMVar portVar-        clientAct sock serverPort--    serverSetup portVar = do-        let hints = defaultHints {-                addrFlags = [AI_PASSIVE]-              , addrSocketType = Datagram-              }-        addr:_ <- getAddrInfo (Just hints) (Just serverAddr) Nothing-        sock <- socket (addrFamily addr) (addrSocketType addr) (addrProtocol addr)-        setSocketOption sock ReuseAddr 1-        bind sock $ addrAddress addr-        serverPort <- socketPort sock-        putMVar portVar serverPort-        return sock---- | Run a client/server pair and synchronize them so that the server--- is started before the client and the specified server action is--- finished before the client closes the 'Socket'.-test :: IO Socket -> (Socket -> IO b) -> IO Socket -> (Socket -> IO c) -> IO ()-test clientSetup clientAct serverSetup serverAct = do-    tid <- myThreadId-    barrier <- newEmptyMVar-    _ <- forkIO $ server barrier-        -- Release MVar if server setup fails-        `E.catch` \(e :: E.SomeException) -> putMVar barrier $ Just e-    client tid barrier-  where-    server barrier =-        E.bracket serverSetup close $ \sock -> do-        serverReady-        Just _ <- timeout 1000000 $ serverAct sock-        putMVar barrier Nothing-      where-        -- | Signal to the client that it can proceed.-        serverReady = putMVar barrier Nothing--    client tid barrier = do-        maybe (return ()) E.throwIO =<< takeMVar barrier-        -- Transfer exceptions to the main thread.-        bracketWithReraise tid clientSetup close $ \res -> do-            Just _ <- timeout 1000000 $ clientAct res-            maybe (return ()) E.throwIO =<< takeMVar barrier---- | Like 'bracket' but catches and reraises the exception in another--- thread, specified by the first argument.-bracketWithReraise :: ThreadId -> IO a -> (a -> IO b) -> (a -> IO ()) -> IO ()-bracketWithReraise tid setup teardown thing =-    E.bracket setup teardown thing-    `E.catch` \ (e :: E.SomeException) -> E.throwTo tid e
+ tests/RegressionSpec.hs view
@@ -0,0 +1,29 @@+{-# LANGUAGE OverloadedStrings #-}+-- | Tests for things that didn't work in the past.+module RegressionSpec (main, spec) where++import Control.Monad+import Network.Socket+import Network.Socket.ByteString++import Test.Hspec++main :: IO ()+main = hspec spec++spec :: Spec+spec = do+    describe "getAddrInfo" $ do+        it "does not cause segfault on macOS 10.8.2 due to AI_NUMERICSERV" $ do+            let hints = defaultHints { addrFlags = [AI_NUMERICSERV] }+            void $ getAddrInfo (Just hints) (Just "localhost") Nothing++    describe "Network.Socket.ByteString.recv" $ do+        it "checks -1 correctly on Windows" $ do+            sock <- socket AF_INET Stream defaultProtocol+            recv sock 1024 `shouldThrow` anyException++    describe "Network.Socket.ByteString.send" $ do+        it "checks -1 correctly on Windows" $ do+            sock <- socket AF_INET Stream defaultProtocol+            send sock "hello world" `shouldThrow` anyException
+ tests/SimpleSpec.hs view
@@ -0,0 +1,353 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE ScopedTypeVariables #-}++module SimpleSpec (main, spec) where++import Control.Concurrent (ThreadId, forkIO, myThreadId)+import Control.Concurrent.MVar (newEmptyMVar, putMVar, takeMVar, readMVar)+import qualified Control.Exception as E+import Control.Monad+import Data.ByteString (ByteString)+import qualified Data.ByteString as S+import qualified Data.ByteString.Char8 as C+import qualified Data.ByteString.Lazy as L+import Network.Socket+import Network.Socket.ByteString+import qualified Network.Socket.ByteString.Lazy as Lazy+import System.Directory+import System.Timeout (timeout)++import Test.Hspec++main :: IO ()+main = hspec spec++spec :: Spec+spec = do+    describe "send" $ do+        it "works well" $ do+            let server sock = recv sock 1024 `shouldReturn` testMsg+                client sock = send sock testMsg+            tcpTest client server++    describe "sendAll" $ do+        it "works well" $ do+            let server sock = recv sock 1024 `shouldReturn` testMsg+                client sock = sendAll sock testMsg+            tcpTest client server++    describe "sendTo" $ do+        it "works well" $ do+            let server sock = recv sock 1024 `shouldReturn` testMsg+                client sock serverPort = do+                    let hints = defaultHints { addrFlags = [AI_NUMERICHOST], addrSocketType = Datagram }+                    addr:_ <- getAddrInfo (Just hints) (Just serverAddr) (Just $ show serverPort)+                    sendTo sock testMsg $ addrAddress addr+            udpTest client server++    describe "sendAllTo" $ do+        it "works well" $ do+            let server sock = recv sock 1024 `shouldReturn` testMsg+                client sock serverPort = do+                    let hints = defaultHints { addrFlags = [AI_NUMERICHOST], addrSocketType = Datagram }+                    addr:_ <- getAddrInfo (Just hints) (Just serverAddr) (Just $ show serverPort)+                    sendAllTo sock testMsg $ addrAddress addr+            udpTest client server++    describe "sendMany" $ do+        it "works well" $ do+            let server sock = recv sock 1024 `shouldReturn` (S.append seg1 seg2)+                client sock = sendMany sock [seg1, seg2]++                seg1 = C.pack "This is a "+                seg2 = C.pack "test message."+            tcpTest client server++    describe "sendManyTo" $ do+        it "works well" $ do+            let server sock = recv sock 1024 `shouldReturn` (S.append seg1 seg2)+                client sock serverPort = do+                    let hints = defaultHints { addrFlags = [AI_NUMERICHOST], addrSocketType = Datagram }+                    addr:_ <- getAddrInfo (Just hints) (Just serverAddr) (Just $ show serverPort)+                    sendManyTo sock [seg1, seg2] $ addrAddress addr++                seg1 = C.pack "This is a "+                seg2 = C.pack "test message."+            udpTest client server++    describe "recv" $ do+        it "works well" $ do+            let server sock = recv sock 1024 `shouldReturn` testMsg+                client sock = send sock testMsg+            tcpTest client server++        it "can treat overflow" $ do+            let server sock = do seg1 <- recv sock (S.length testMsg - 3)+                                 seg2 <- recv sock 1024+                                 let msg = S.append seg1 seg2+                                 msg `shouldBe` testMsg+                client sock = send sock testMsg+            tcpTest client server++        it "returns empty string at EOF" $ do+            let client s = recv s 4096 `shouldReturn` S.empty+                server s = shutdown s ShutdownSend+            tcpTest client server++    describe "recvFrom" $ do+        it "works well" $ do+            let server sock = do (msg, _) <- recvFrom sock 1024+                                 testMsg `shouldBe` msg+                client sock = do+                    addr <- getPeerName sock+                    sendTo sock testMsg addr+            tcpTest client server+        it "can treat overflow" $ do+            let server sock = do (seg1, _) <- recvFrom sock (S.length testMsg - 3)+                                 (seg2, _) <- recvFrom sock 1024+                                 let msg = S.append seg1 seg2+                                 testMsg `shouldBe` msg++                client sock = send sock testMsg+            tcpTest client server++    describe "UserTimeout" $ do+        it "can be set" $ do+            when (isSupportedSocketOption UserTimeout) $ do+              sock <- socket AF_INET Stream defaultProtocol+              setSocketOption sock UserTimeout 1000+              getSocketOption sock UserTimeout `shouldReturn` 1000+              setSocketOption sock UserTimeout 2000+              getSocketOption sock UserTimeout `shouldReturn` 2000+              close sock++    -- On various BSD systems the peer credentials are exchanged during+    -- connect(), and this does not happen with `socketpair()`.  Therefore,+    -- we must actually set up a listener and connect, rather than use a+    -- socketpair().+    --+    describe "getPeerCredential" $ do+        it "can return something" $ do+            when isUnixDomainSocketAvailable $ do+                -- It would be useful to check that we did not get garbage+                -- back, but rather the actual uid of the test program.  For+                -- that we'd need System.Posix.User, but that is not available+                -- under Windows.  For now, accept the risk that we did not get+                -- the right answer.+                --+                let client sock = do+                        (_, uid, _) <- getPeerCredential sock+                        uid `shouldNotBe` Nothing+                    server (sock, _) = do+                        (_, uid, _) <- getPeerCredential sock+                        uid `shouldNotBe` Nothing+                unixTest client server+        {- The below test fails on many *BSD systems, because the getsockopt()+           call that underlies getpeereid() does not have the same meaning for+           all address families, but the C-library was not checking that the+           provided sock is an AF_UNIX socket.  This will fixed some day, but+           we should not fail on those systems in the mean-time.  The upstream+           C-library fix is to call getsockname() and check the address family+           before calling `getpeereid()`.  We could duplicate that in our own+           code, and then this test would work on those platforms that have+           `getpeereid()` and not the SO_PEERCRED socket option.++        it "return nothing for non-UNIX-domain socket" $ do+            when isUnixDomainSocketAvailable $ do+                s <- socket AF_INET Stream defaultProtocol+                cred1 <- getPeerCredential s+                cred1 `shouldBe` (Nothing,Nothing,Nothing)+        -}++    describe "getAddrInfo" $ do+        it "works for IPv4 address" $ do+            let hints = defaultHints { addrFlags = [AI_NUMERICHOST, AI_ADDRCONFIG] }+            AddrInfo{addrAddress = (SockAddrInet _ hostAddr)}:_ <-+                getAddrInfo (Just hints) (Just "127.128.129.130") Nothing+            hostAddressToTuple hostAddr `shouldBe` (0x7f, 0x80, 0x81, 0x82)+#if defined(IPV6_SOCKET_SUPPORT)+        it "works for IPv6 address" $ do+            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+            hostAddress6ToTuple hostAddr+                `shouldBe` (0x2001, 0x0db8, 0x85a3, 0x0000, 0x0000, 0x8a2e, 0x0370, 0x7334)+#endif++    describe "unix sockets" $ do+        it "basic unix sockets end-to-end" $ do+            when isUnixDomainSocketAvailable $ do+                let client sock = send sock testMsg+                    server (sock, addr) = do+                      recv sock 1024 `shouldReturn` testMsg+                      addr `shouldBe` (SockAddrUnix "")+                unixTest client server++    describe "Lazy.sendAll" $ do+        it "works well" $ do+            let server sock = recv sock 1024 `shouldReturn` testMsg+                client sock = Lazy.sendAll sock $ L.fromChunks [testMsg]+            tcpTest client server++------------------------------------------------------------------------++serverAddr :: String+serverAddr = "127.0.0.1"++testMsg :: ByteString+testMsg = "This is a test message."++unixAddr :: String+unixAddr = "/tmp/network-test"++------------------------------------------------------------------------+-- Test helpers++-- | Establish a connection between client and server and then run+-- 'clientAct' and 'serverAct', in different threads.  Both actions+-- get passed a connected 'Socket', used for communicating between+-- client and server.  'unixTest' makes sure that the 'Socket' is+-- closed after the actions have run.+unixTest :: (Socket -> IO a) -> ((Socket, SockAddr) -> IO b) -> IO ()+unixTest clientAct serverAct = do+    test clientSetup clientAct serverSetup server+  where+    clientSetup = do+        sock <- socket AF_UNIX Stream defaultProtocol+        connect sock (SockAddrUnix unixAddr)+        return sock++    serverSetup = do+        sock <- socket AF_UNIX Stream defaultProtocol+        unlink unixAddr -- just in case+        bind sock (SockAddrUnix unixAddr)+        listen sock 1+        return sock++    server sock = E.bracket (accept sock) (killClientSock . fst) serverAct++    unlink file = do+        exist <- doesFileExist file+        when exist $ removeFile file++    killClientSock sock = do+        shutdown sock ShutdownBoth+        close sock+        unlink unixAddr++-- | Establish a connection between client and server and then run+-- 'clientAct' and 'serverAct', in different threads.  Both actions+-- get passed a connected 'Socket', used for communicating between+-- client and server.  'tcpTest' makes sure that the 'Socket' is+-- closed after the actions have run.+tcpTest :: (Socket -> IO a) -> (Socket -> IO b) -> IO ()+tcpTest clientAct serverAct = do+    portVar <- newEmptyMVar+    test (clientSetup portVar) clientAct (serverSetup portVar) server+  where+    clientSetup portVar = do+        let hints = defaultHints { addrSocketType = Stream }+        serverPort <- readMVar portVar+        addr:_ <- getAddrInfo (Just hints) (Just serverAddr) (Just $ show serverPort)+        sock <- socket (addrFamily addr) (addrSocketType addr) (addrProtocol addr)+#if !defined(mingw32_HOST_OS)+        fd <- fdSocket sock+        getNonBlock fd `shouldReturn` True+        getCloseOnExec fd `shouldReturn` False+#endif+        connect sock $ addrAddress addr+        return sock++    serverSetup portVar = do+        let hints = defaultHints {+                addrFlags = [AI_PASSIVE]+              , addrSocketType = Stream+              }+        addr:_ <- getAddrInfo (Just hints) (Just serverAddr) Nothing+        sock <- socket (addrFamily addr) (addrSocketType addr) (addrProtocol addr)+        fd <- fdSocket sock+#if !defined(mingw32_HOST_OS)+        getNonBlock fd `shouldReturn` True+        getCloseOnExec fd `shouldReturn` False+#endif+        setSocketOption sock ReuseAddr 1+        setCloseOnExecIfNeeded fd+#if !defined(mingw32_HOST_OS)+        getCloseOnExec fd `shouldReturn` True+#endif+        bind sock $ addrAddress addr+        listen sock 1+        serverPort <- socketPort sock+        putMVar portVar serverPort+        return sock++    server sock = do+        (clientSock, _) <- accept sock+#if !defined(mingw32_HOST_OS)+        fd <- fdSocket clientSock+        getNonBlock fd `shouldReturn` True+        getCloseOnExec fd `shouldReturn` True+#endif+        _ <- serverAct clientSock+        close clientSock++-- | Create an unconnected 'Socket' for sending UDP and receiving+-- datagrams and then run 'clientAct' and 'serverAct'.+udpTest :: (Socket -> PortNumber -> IO a) -> (Socket -> IO b) -> IO ()+udpTest clientAct serverAct = do+    portVar <- newEmptyMVar+    test clientSetup (client portVar) (serverSetup portVar) serverAct+  where+    clientSetup = socket AF_INET Datagram defaultProtocol++    client portVar sock = do+        serverPort <- readMVar portVar+        clientAct sock serverPort++    serverSetup portVar = do+        let hints = defaultHints {+                addrFlags = [AI_PASSIVE]+              , addrSocketType = Datagram+              }+        addr:_ <- getAddrInfo (Just hints) (Just serverAddr) Nothing+        sock <- socket (addrFamily addr) (addrSocketType addr) (addrProtocol addr)+        setSocketOption sock ReuseAddr 1+        bind sock $ addrAddress addr+        serverPort <- socketPort sock+        putMVar portVar serverPort+        return sock++-- | Run a client/server pair and synchronize them so that the server+-- is started before the client and the specified server action is+-- finished before the client closes the 'Socket'.+test :: IO Socket -> (Socket -> IO b) -> IO Socket -> (Socket -> IO c) -> IO ()+test clientSetup clientAct serverSetup serverAct = do+    tid <- myThreadId+    barrier <- newEmptyMVar+    _ <- forkIO $ server barrier+    client tid barrier+  where+    server barrier = do+        E.bracket serverSetup close $ \sock -> do+            serverReady+            Just _ <- timeout 1000000 $ serverAct sock+            putMVar barrier ()+      where+        -- | Signal to the client that it can proceed.+        serverReady = putMVar barrier ()++    client tid barrier = do+        takeMVar barrier+        -- Transfer exceptions to the main thread.+        bracketWithReraise tid clientSetup close $ \res -> do+            Just _ <- timeout 1000000 $ clientAct res+            takeMVar barrier++-- | Like 'bracket' but catches and reraises the exception in another+-- thread, specified by the first argument.+bracketWithReraise :: ThreadId -> IO a -> (a -> IO b) -> (a -> IO ()) -> IO ()+bracketWithReraise tid setup teardown thing =+    E.bracket setup teardown thing+    `E.catch` \ (e :: E.SomeException) -> E.throwTo tid e
tests/doctests.hs view
@@ -1,20 +1,15 @@-import Test.DocTest+module Main where +import Build_doctests (flags, pkgs, module_sources)+import Data.Foldable (traverse_)+import Data.List (isSuffixOf, isPrefixOf)+import Test.DocTest (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"-  ]+main = do+    traverse_ putStrLn args+    doctest args+  where+    builddir = filter ("build" `isSuffixOf`) $ filter ("-i" `isPrefixOf`) flags+    addinc path = "-I" ++ drop 2 path ++ "/include"+    args = map addinc builddir ++ flags ++ pkgs ++ module_sources