packages feed

network-bsd 2.8.0.0 → 2.8.1.0

raw patch · 3 files changed

+738/−8 lines, 3 filesdep +deepseqdep ~basedep ~network

Dependencies added: deepseq

Dependency ranges changed: base, network

Files

+ CHANGELOG.md view
@@ -0,0 +1,7 @@+## 2.8.1.0++- First version to support `network-3.0.0.0`+- Fix dead-lock in `getProtocolEntries` and make the high-level composite `get*Entries` operations atomic+- Reexport `HostAddress` and `Family` (from `network`)+- Provide `ifNameToIndex` unconditionally+- Add `NFData` instances for `ServiceEntry`, `ProtocolEntry`, `HostEntry`, and `NetworkEntry`
+ Network/BSD.hsc view
@@ -0,0 +1,660 @@+{-# LANGUAGE CPP, NondecreasingIndentation, DeriveDataTypeable, BangPatterns #-}++-----------------------------------------------------------------------------+-- |+-- Module      :  Network.BSD+-- Copyright   :  (c) The University of Glasgow 2001+-- SPDX-License-Identifier: BSD-3-Clause+--+-- Maintainer  :  libraries@haskell.org+-- Stability   :  experimental+-- Portability :  non-portable+--+-- The "Network.BSD" module defines Haskell bindings to network+-- programming functionality (mostly [network database operations](http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/netdb.h.html))+-- provided by BSD Unix derivatives.+--+-- __NOTE__: Some of the types are reexported from "Network.Socket" in order to make the @network-bsd@ API self-contained.+--+-- == Windows compatibility+--+-- The following functions are not exported by "Network.BSD" on the+-- Windows platform:+--+-- * 'getHostEntries', 'setHostEntry', 'getHostEntry', 'endHostEntry'+-- * 'getServiceEntries', 'getServiceEntry', 'setServiceEntry', 'endServiceEntry'+-- * 'getProtocolEntries', 'setProtocolEntry', 'getProtocolEntry', 'endProtocolEntry'+-- * 'getNetworkByName', 'getNetworkByAddr', 'getNetworkEntries',+--   'setNetworkEntry', 'getNetworkEntry', 'endNetworkEntry'+--+-----------------------------------------------------------------------------++#include "HsNet.h"+##include "HsNetDef.h"++module Network.BSD+    (+    -- * Host names and network addresses+      N.HostName+    , N.HostAddress+      -- NB: We're explicit here to reduce the risk of inadvertently leaking through new constructors w/o reflecting this in @network-bsd@'s API version+    , N.Family(AF_UNSPEC, AF_UNIX, AF_INET, AF_INET6, AF_IMPLINK, AF_PUP, AF_CHAOS, AF_NS, AF_NBS, AF_ECMA, AF_DATAKIT, AF_CCITT, AF_SNA, AF_DECnet, AF_DLI, AF_LAT, AF_HYLINK, AF_APPLETALK, AF_ROUTE, AF_NETBIOS, AF_NIT, AF_802, AF_ISO, AF_OSI, AF_NETMAN, AF_X25, AF_AX25, AF_OSINET, AF_GOSSIP, AF_IPX, Pseudo_AF_XTP, AF_CTF, AF_WAN, AF_SDL, AF_NETWARE, AF_NDD, AF_INTF, AF_COIP, AF_CNT, Pseudo_AF_RTIP, Pseudo_AF_PIP, AF_SIP, AF_ISDN, Pseudo_AF_KEY, AF_NATM, AF_ARP, Pseudo_AF_HDRCMPLT, AF_ENCAP, AF_LINK, AF_RAW, AF_RIF, AF_NETROM, AF_BRIDGE, AF_ATMPVC, AF_ROSE, AF_NETBEUI, AF_SECURITY, AF_PACKET, AF_ASH, AF_ECONET, AF_ATMSVC, AF_IRDA, AF_PPPOX, AF_WANPIPE, AF_BLUETOOTH, AF_CAN)+    , getHostName++    , HostEntry(..)+    , getHostByName+    , getHostByAddr+    , hostAddress++#if defined(HAVE_GETHOSTENT) && !defined(mingw32_HOST_OS)+    , getHostEntries++    -- ** Low level functionality+    , setHostEntry+    , getHostEntry+    , endHostEntry+#endif++    -- * Service names+    , ServiceEntry(..)+    , N.ServiceName+    , N.PortNumber+    , getServiceByName+    , getServiceByPort+    , getServicePortNumber++#if !defined(mingw32_HOST_OS)+    , getServiceEntries++    -- ** Low level functionality+    , getServiceEntry+    , setServiceEntry+    , endServiceEntry+#endif++    -- * Protocol names+    , ProtocolName+    , N.ProtocolNumber+    , ProtocolEntry(..)+    , getProtocolByName+    , getProtocolByNumber+    , getProtocolNumber+    , N.defaultProtocol++#if !defined(mingw32_HOST_OS)+    , getProtocolEntries+    -- ** Low level functionality+    , setProtocolEntry+    , getProtocolEntry+    , endProtocolEntry+#endif++    -- * Network names+    , NetworkName+    , NetworkAddr+    , NetworkEntry(..)++#if !defined(mingw32_HOST_OS)+    , getNetworkByName+    , getNetworkByAddr+    , getNetworkEntries+    -- ** Low level functionality+    , setNetworkEntry+    , getNetworkEntry+    , endNetworkEntry+#endif++    -- * Interface names+    , N.ifNameToIndex++    ) where++import qualified Network.Socket as N++import Control.Concurrent (MVar, newMVar, withMVar)+import qualified Control.Exception as E+import Foreign.C.String (CString, peekCString, withCString)+#if defined(mingw32_HOST_OS)+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.DeepSeq (NFData(rnf))+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.++-- | Representation of the POSIX @servent@ structure defined in [<netdb.h>](http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/netdb.h.html).+data ServiceEntry  =+  ServiceEntry  {+     serviceName     :: N.ServiceName,    -- ^ Official service name+     serviceAliases  :: [N.ServiceName],  -- ^ aliases+     servicePort     :: N.PortNumber,     -- ^ Port Number+     serviceProtocol :: ProtocolName      -- ^ Protocol to use+  } deriving (Show, Typeable)++-- | @since 2.8.1.0+instance NFData ServiceEntry where+   -- TODO: PortNumber is a newtype over Word16; add NFData instance to `network`+   rnf (ServiceEntry n a !_pn pr) = rnf (n,a,pr)++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(mingw32_HOST_OS)+                        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 :: N.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 'N.PortNumber' and 'ProtocolName'.+getServiceByPort :: N.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 'N.PortNumber' corresponding to the 'N.ServiceName'.+getServicePortNumber :: N.ServiceName -> IO N.PortNumber+getServicePortNumber name = do+    (ServiceEntry _ _ port _) <- getServiceByName name "tcp"+    return port++#if !defined(mingw32_HOST_OS)++-- | @getservent(3)@.+getServiceEntry :: IO ServiceEntry+getServiceEntry = withLock getServiceEntry'++getServiceEntry' :: IO ServiceEntry+getServiceEntry' = do+  throwNoSuchThingIfNull "Network.BSD.getServiceEntry" "no such service entry"+    $ c_getservent+  >>= peek++foreign import ccall unsafe "getservent" c_getservent :: IO (Ptr ServiceEntry)++-- | @setservent(3)@.+setServiceEntry :: Bool -> IO ()+setServiceEntry = withLock . setServiceEntry'++setServiceEntry' :: Bool -> IO ()+setServiceEntry' flg = c_setservent (fromBool flg)++foreign import ccall unsafe  "setservent" c_setservent :: CInt -> IO ()++-- | @endservent(3)@.+endServiceEntry :: IO ()+endServiceEntry = withLock $ c_endservent++foreign import ccall unsafe  "endservent" c_endservent :: IO ()++-- | Retrieve list of all 'ServiceEntry' via @getservent(3)@.+getServiceEntries :: Bool -> IO [ServiceEntry]+getServiceEntries stayOpen = withLock $ do+  setServiceEntry' stayOpen+  getEntries getServiceEntry' c_endservent+#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,++-- | Representation of the POSIX @protoent@ structure defined in [<netdb.h>](http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/netdb.h.html).+data ProtocolEntry =+  ProtocolEntry  {+     protoName    :: ProtocolName,      -- ^ Official name+     protoAliases :: [ProtocolName],    -- ^ aliases+     protoNumber  :: N.ProtocolNumber   -- ^ Protocol number+  } deriving (Read, Show, Typeable)++-- | @since 2.8.1.0+instance NFData ProtocolEntry where+   -- NB: deepseq-1.3 didn't have `NFData CInt` yet; but we don't need it+   rnf (ProtocolEntry na a !_nu) = rnf (na,a)++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(mingw32_HOST_OS)+         -- 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"+++-- | @getprotobyname(3)@.+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)++-- | @getprotobynumber(3)@.+getProtocolByNumber :: N.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)++-- | @getprotobyname(3)@.+getProtocolNumber :: ProtocolName -> IO N.ProtocolNumber+getProtocolNumber proto = do+ (ProtocolEntry _ _ num) <- getProtocolByName proto+ return num++#if !defined(mingw32_HOST_OS)+-- | @getprotoent(3)@.+getProtocolEntry :: IO ProtocolEntry    -- Next Protocol Entry from DB+getProtocolEntry = withLock getProtocolEntry'++getProtocolEntry' :: IO ProtocolEntry+getProtocolEntry' = do+  ent <- throwNoSuchThingIfNull "Network.BSD.getProtocolEntry" "no such protocol entry"+           $ c_getprotoent+  peek ent++foreign import ccall unsafe  "getprotoent" c_getprotoent :: IO (Ptr ProtocolEntry)++-- | @setprotoent(3)@.+setProtocolEntry :: Bool -> IO ()       -- Keep DB Open ?+setProtocolEntry = withLock . setProtocolEntry'++setProtocolEntry' :: Bool -> IO ()       -- Keep DB Open ?+setProtocolEntry' flg = c_setprotoent (fromBool flg)++foreign import ccall unsafe "setprotoent" c_setprotoent :: CInt -> IO ()++-- | @endprotoent(3)@.+endProtocolEntry :: IO ()+endProtocolEntry = withLock $ c_endprotoent++foreign import ccall unsafe "endprotoent" c_endprotoent :: IO ()++-- | Retrieve list of all 'ProtocolEntry' via @getprotoent(3)@.+getProtocolEntries :: Bool -> IO [ProtocolEntry]+getProtocolEntries stayOpen = withLock $ do+  setProtocolEntry' stayOpen+  getEntries getProtocolEntry' c_endprotoent++#endif++-- ---------------------------------------------------------------------------+-- Host lookups++-- | Representation of the POSIX @hostent@ structure defined in [<netdb.h>](http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/netdb.h.html).+data HostEntry =+  HostEntry  {+     hostName      :: N.HostName,         -- ^ Official name of the host+     hostAliases   :: [N.HostName],       -- ^ Alternative names of the host+     hostFamily    :: N.Family,           -- ^ Address type (currently @AF_INET@)+     hostAddresses :: [N.HostAddress]     -- ^ Set of network addresses for the host+  } deriving (Read, Show, Typeable)++-- | @since 2.8.1.0+instance NFData HostEntry where+   -- TODO: NFData N.Family+   rnf (HostEntry n al !_f ad) = rnf (n,al,ad)++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(mingw32_HOST_OS)+                        hostFamily     = N.unpackFamily (fromIntegral (h_addrtype :: CShort)),+#else+                        hostFamily     = N.unpackFamily h_addrtype,+#endif+                        hostAddresses  = h_addr_list+                })++   poke = throwUnsupportedOperationPoke "HostEntry"+++-- convenience function:+-- | Convenience function extracting one address in a 'HostEntry'.+-- Returns 'error' if 'HostEntry' contains no addresses.+hostAddress :: HostEntry -> N.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 'N.HostName' to IPv4 address.+getHostByName :: N.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 :: N.Family -> N.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)) (N.packFamily family)+ >>= peek++foreign import CALLCONV safe "gethostbyaddr"+   c_gethostbyaddr :: Ptr N.HostAddress -> CInt -> CInt -> IO (Ptr HostEntry)++#if defined(HAVE_GETHOSTENT) && !defined(mingw32_HOST_OS)+-- | @gethostent(3)@.+getHostEntry :: IO HostEntry+getHostEntry = withLock getHostEntry++getHostEntry' :: IO HostEntry+getHostEntry' = do+  throwNoSuchThingIfNull "Network.BSD.getHostEntry" "unable to retrieve host entry"+    $ c_gethostent+  >>= peek++foreign import ccall unsafe "gethostent" c_gethostent :: IO (Ptr HostEntry)++-- | @sethostent(3)@.+setHostEntry :: Bool -> IO ()+setHostEntry = withLock . setHostEntry'++setHostEntry' :: Bool -> IO ()+setHostEntry' flg = c_sethostent (fromBool flg)++foreign import ccall unsafe "sethostent" c_sethostent :: CInt -> IO ()++-- | @endhostent(3)@.+endHostEntry :: IO ()+endHostEntry = withLock $ c_endhostent++foreign import ccall unsafe "endhostent" c_endhostent :: IO ()++-- | Retrieve list of all 'HostEntry' via @gethostent(3)@.+getHostEntries :: Bool -> IO [HostEntry]+getHostEntries stayOpen = withLock $ do+  setHostEntry' stayOpen+  getEntries getHostEntry' c_endhostent++#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++-- | Representation of the POSIX @netent@ structure defined in [<netdb.h>](http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/netdb.h.html).+data NetworkEntry =+  NetworkEntry {+     networkName        :: NetworkName,   -- ^ Official network name+     networkAliases     :: [NetworkName], -- ^ aliases+     networkFamily      :: N.Family,      -- ^ Network address type+     networkAddress     :: NetworkAddr    -- ^ Network number+   } deriving (Read, Show, Typeable)++-- | @since 2.8.1.0+instance NFData NetworkEntry where+   -- NB: We avoid relying on the `NFData CULong` instance which isn't available in deepseq-1.3 yet+   rnf (NetworkEntry n al !_f !_ad) = rnf (n,al)++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    = N.unpackFamily (fromIntegral (n_addrtype :: CInt)),+                        networkAddress   = n_net+                })++   poke = throwUnsupportedOperationPoke "NetworkEntry"+++#if !defined(mingw32_HOST_OS)+-- | @getnetbyname(3)@.+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)++-- | @getnetbyaddr(3)@.+getNetworkByAddr :: NetworkAddr -> N.Family -> IO NetworkEntry+getNetworkByAddr addr family = withLock $ do+ throwNoSuchThingIfNull "Network.BSD.getNetworkByAddr" "no such network entry"+   $ c_getnetbyaddr addr (N.packFamily family)+ >>= peek++foreign import ccall unsafe "getnetbyaddr"+   c_getnetbyaddr  :: NetworkAddr -> CInt -> IO (Ptr NetworkEntry)++-- | @getnetent(3)@.+getNetworkEntry :: IO NetworkEntry+getNetworkEntry = withLock getNetworkEntry'++getNetworkEntry' :: IO NetworkEntry+getNetworkEntry' = 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+--+-- @setnetent(3)@.+setNetworkEntry :: Bool -> IO ()+setNetworkEntry = withLock . setNetworkEntry'++setNetworkEntry' :: Bool -> IO ()+setNetworkEntry' flg = c_setnetent (fromBool flg)++foreign import ccall unsafe "setnetent" c_setnetent :: CInt -> IO ()++-- | Close the connection to the network name database.+--+-- @endnetent(3)@.+endNetworkEntry :: IO ()+endNetworkEntry = withLock $ c_endnetent++foreign import ccall unsafe "endnetent" c_endnetent :: IO ()++-- | Get the list of network entries via @getnetent(3)@.+getNetworkEntries :: Bool -> IO [NetworkEntry]+getNetworkEntries stayOpen = withLock $ do+  setNetworkEntry' stayOpen+  getEntries getNetworkEntry' c_endnetent+#endif++-- Mutex for name service lockdown++{-# NOINLINE lock #-}+lock :: MVar ()+lock = unsafePerformIO $ N.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(2)@.+getHostName :: IO N.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-bsd.cabal view
@@ -1,24 +1,87 @@-cabal-version:  1.22+cabal-version:  1.12 name:           network-bsd-version:        2.8.0.0+version:        2.8.1.0 license:        BSD3 license-file:   LICENSE-maintainer:     Kazu Yamamoto-synopsis:       Network.BSD+maintainer:     Kazu Yamamoto, Herbert Valerio Riedel+synopsis:       POSIX network database (<netdb.h>) API description:-  This package reexports the "Network.BSD" module split from the <https://hackage.haskell.org/package/network-2.8.0.0 network-2.8.0.0> package.+  This package provides Haskell bindings to the+  the [POSIX network database (<netdb.h>) API](http://pubs.opengroup.org/onlinepubs/009696699/basedefs/netdb.h.html).   .-  See newer versions of <https://hackage.haskell.org/package/network-bsd network-bsd> for more information.+  === Relationship to the @network@ package+  .+  The @network@ package version 2.* series provides "Network.BSD" but+  it is removed starting with @network@ version 3.0.+  .+  This package provides the "Network.BSD" module split off from the+  <https://hackage.haskell.org/package/network network package>.+  .+  If in addition to the @network@'s modules also "Network.BSD" is+  necessary, add @network-bsd@ to your dependencies like so:+  .+  > library+  >     build-depends: network     >= 2.7 && < 3.1+  >                  , network-bsd >= 2.7 && < 2.9+  .+  I.e. you can control the version of the @network@ package+  independently.+  .+  __NOTE__: Starting with @network-bsd-2.8.1.0@ the APIs of @network@+  and @network-bsd@ evolve differently, and consequently the+  versioning doesn't match up anymore! Moreover, also starting with+  version @network-bsd-2.8.1.0@ this package requires @network >= 3@+  in order to avoid module name clashes with @network < 3@'s+  "Network.BSD" module.+  .+  However, @network-bsd-2.7.0.0@ and @network-bsd-2.8.0.0@ passes thru+  the "Network.BSD" module from @network-2.7.*@ and @network-2.8.*@+  respectively in a non-clashing way via Cabal's+  <https://www.haskell.org/cabal/users-guide/developing-packages.html#pkg-field-library-reexported-modules reexported-modules>+  feature while ensuring a well-defined+  <https://pvp.haskell.org/ API versioning> of the observable API of+  @network-bsd@. This is why the example above supporting a wide range+  of @network@ versions works by including version 2.7.0.0 in the+  required version range of @network-bsd@.  category:       Network build-type:     Simple homepage:       https://github.com/haskell/network-bsd bug-reports:    https://github.com/haskell/network-bsd/issues+tested-with:   GHC == 7.8.4+             , GHC == 7.10.3+             , GHC == 8.0.2+             , GHC == 8.2.2+             , GHC == 8.4.4+             , GHC == 8.6.3+extra-source-files: CHANGELOG.md  library   default-language: Haskell2010-  reexported-modules: Network.BSD-  build-depends: base >= 4.8 && < 5, network == 2.8.0.*+  other-extensions: CPP, NondecreasingIndentation+  exposed-modules: Network.BSD+  build-depends: base    >= 4.7 && < 5+               , deepseq >= 1.3.0.0 && < 1.5+               -- NOTES on `network` depdendency+               --+               -- `network-bsd` heavily relies on `network`'s+               -- exported CPP headers!  make sure that `network`+               -- doesn't inadvertently break/change its CPP+               -- headers before advertising support for new+               -- versions of `network`.+               --+               -- Moreover, `network-bsd` reexports entities from+               -- `network` so we need to be very conservative+               -- with the bounds to avoid leaking through API+               -- changes that aren't reflected in `network-bsd`'s+               -- API version.+               , network >= 3.0.0.0 && < 3.0.1+  build-tools: hsc2hs >= 0.67 && < 0.69+  ghc-options: -Wall++  if os(windows) && impl(ghc >= 7.10)+    -- See https://github.com/haskell/network/pull/362+    cpp-options: -D_WIN32_WINNT=0x0600  source-repository head   type:     git