network-fancy 0.1.5.2 → 0.2.0
raw patch · 7 files changed
+271/−112 lines, 7 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
+ Network.Fancy: AddressTooLongException :: NetworkException
+ Network.Fancy: GetAdddrInfoException :: !CInt -> NetworkException
+ Network.Fancy: NoSuchHostException :: NetworkException
+ Network.Fancy: SocketException :: !String -> !Socket -> !Errno -> NetworkException
+ Network.Fancy: UnsupportedAddressFamilyException :: NetworkException
+ Network.Fancy: data NetworkException
Files
- COPYING +1/−1
- Network/Fancy.hsc +89/−77
- Network/Fancy/Error.hs +102/−0
- Network/Fancy/Internal.hs +23/−0
- cbits.c +1/−1
- changelog.md +6/−0
- network-fancy.cabal +49/−33
COPYING view
@@ -1,4 +1,4 @@-Copyright (c) 2008, Taru Karttunen+Copyright (c) 2008-2014, Taru Karttunen All rights reserved. Redistribution and use in source and binary forms, with or without
Network/Fancy.hsc view
@@ -6,12 +6,13 @@ -- * Datagram clients connectDgram, withDgram, StringLike, recv,send, closeSocket, -- * Servers- ServerSpec(..), serverSpec, + ServerSpec(..), serverSpec, Threading(..), Reverse(..), streamServer, dgramServer, sleepForever, -- * Other getCurrentHost,- Socket+ Socket,+ NetworkException(..), ) where import Control.Concurrent@@ -28,7 +29,8 @@ #else import Foreign hiding (unsafeForeignPtrToPtr) #endif-import Foreign.C+import Foreign.C(CString,peekCString,withCString,Errno(..),eAGAIN,eINTR,eWOULDBLOCK,getErrno,eINPROGRESS)+import Foreign.C.Types import Foreign.ForeignPtr.Unsafe (unsafeForeignPtrToPtr) import Numeric(showHex) import System.IO(Handle, hClose, IOMode(ReadWriteMode))@@ -44,6 +46,9 @@ import GHC.Conc(asyncDoProc) #endif +import Network.Fancy.Error+import Network.Fancy.Internal+ #ifndef WINDOWS #include <arpa/inet.h> #include <errno.h>@@ -81,11 +86,11 @@ #endif /* WINDOWS */ setNonBlockingFD' :: FD -> IO ()-setNonBlockingFD' =+setNonBlockingFD' fd = #if __GLASGOW_HASKELL__ < 611- System.Posix.Internals.setNonBlockingFD+ System.Posix.Internals.setNonBlockingFD fd #else- flip System.Posix.Internals.setNonBlockingFD True+ System.Posix.Internals.setNonBlockingFD fd True #endif type HostName = String@@ -114,35 +119,38 @@ -- | Send the string as one chunk send :: StringLike string => Socket -> string -> IO ()-send (Socket s) bs = B.unsafeUseAsCStringLen (toBS bs) $ \(ptr,len) -> do- r <- throwErrnoIfMinus1RetryMayBlock "send" (c_send s (castPtr ptr) (fromIntegral len) 0) (threadWaitWrite (fromIntegral s))- when (r/=fromIntegral len) $ fail "send: partial packet sent!"+send (Socket s) bs =+ let loop ptr len = do+ r <- writeOp "send" s (c_send s (castPtr ptr) (fromIntegral len) 0)+ let r' = fromIntegral r+ if r' >= len then return () else loop (plusPtr ptr r') (r' - len)+ in B.unsafeUseAsCStringLen (toBS bs) $ \(ptr,len) -> loop ptr len -- | Receive one chunk with given maximum size recv :: StringLike string => Socket -> Int -> IO string recv (Socket s) len= fmap fromBS ( B.createAndTrim len $ \ptr -> do- r <- throwErrnoIfMinus1RetryMayBlock "recv" (c_recv s (castPtr ptr) (fromIntegral len) 0) (threadWaitRead (fromIntegral s))+ r <- readOp "recv" s (c_recv s (castPtr ptr) (fromIntegral len) 0) return $ fromIntegral r) recvFrom :: StringLike string => Socket -> Int -> SocketAddress -> IO (string,SocketAddress) recvFrom (Socket s) buflen (SA _ salen) = do sa <- mallocForeignPtrBytes salen withForeignPtr sa $ \sa_ptr -> do- str<- B.createAndTrim buflen $ \ptr -> do+ (str,len) <- B.createAndTrim' buflen $ \ptr -> do with (fromIntegral salen) $ \salen_ptr -> do- fmap fromIntegral $ throwErrnoIfMinus1RetryMayBlock "recvfrom"- (c_recvfrom s ptr (fromIntegral buflen) 0 sa_ptr salen_ptr)- (threadWaitRead (fromIntegral s))- return (fromBS str, SA sa salen)+ rd <- readOp "recvfrom" s $ c_recvfrom s ptr (fromIntegral buflen) 0 sa_ptr salen_ptr+ len <- peek salen_ptr+ return (0,fromIntegral rd, fromIntegral len)+ return (fromBS str, SA sa len) sendTo :: StringLike string => SocketAddress -> Socket -> string -> IO () sendTo (SA sa salen) (Socket s) str = do withForeignPtr sa $ \sa_ptr -> do- B.unsafeUseAsCStringLen (toBS str) $ \(ptr,len) -> do- r <- throwErrnoIfMinus1RetryMayBlock "sendTo" - (c_sendto s (castPtr ptr) (fromIntegral len) 0 sa_ptr (fromIntegral salen))- (threadWaitWrite (fromIntegral s))- when (r/=fromIntegral len) $ fail "sendTo: partial packet sent!"+ let loop ptr len = do+ r <- writeOp "sendTo" s $ c_sendto s (castPtr ptr) (fromIntegral len) 0 sa_ptr (fromIntegral salen)+ let r' = fromIntegral r+ if r' >= len then return () else loop (plusPtr ptr r') (r' - len)+ B.unsafeUseAsCStringLen (toBS str) $ \(ptr,len) -> loop ptr len foreign import CALLCONV SAFE_ON_WIN "recv" c_recv :: CInt -> Ptr Word8 -> CSize -> CInt -> IO (#type ssize_t) foreign import CALLCONV SAFE_ON_WIN "send" c_send :: CInt -> Ptr Word8 -> CSize -> CInt -> IO (#type ssize_t)@@ -151,7 +159,7 @@ -- | Close the socket specified. closeSocket :: Socket -> IO ()-closeSocket (Socket fd) = throwErrnoIfMinus1_ "close" $ c_close fd+closeSocket sock@(Socket fd) = throwIfError_ sock "close" $ c_close fd foreign import CALLCONV unsafe "bind" c_bind :: CInt -> Ptr () -> (SLen) -> IO CInt foreign import CALLCONV unsafe "listen" c_listen :: CInt -> CInt -> IO CInt@@ -163,7 +171,6 @@ foreign import CALLCONV unsafe "close" c_close :: CInt -> IO CInt #endif -newtype Socket = Socket CInt -- | Open a datagram (udp) socket for the given block and close it afterwards. withDgram :: Address -> (Socket -> IO a) -> IO a@@ -192,17 +199,18 @@ connect :: CType -> SocketAddress -> IO Socket connect stype (SA sa len) = do fam <- getFamily (SA sa len)- s <- throwErrnoIfMinus1 "socket" $ c_socket fam stype 0+ s <- newsock fam stype setNonBlockingFD' s+ let sock = Socket s let loop = do r <- withForeignPtr sa $ \ptr -> c_connect s ptr (fromIntegral len) err <- getErrno case r of -1 | err == eINTR -> do loop | err == eINPROGRESS -> do threadWaitWrite (fromIntegral s) soe <- getsockopt_error s- if soe==0 then return (Socket s) else fail "connect"- | otherwise -> do fail "connect"- _ -> do return $ Socket s+ if soe==0 then return sock else throwNetworkException sock "connect" (Errno soe)+ | otherwise -> do throwNetworkException sock "connect" err+ _ -> do return sock loop foreign import ccall unsafe getsockopt_error :: CInt -> IO CInt@@ -212,10 +220,10 @@ getFamily :: SocketAddress -> IO CFamily getFamily (SA sa _) = worker >>= return . fromIntegral where worker :: IO #type sa_family_t- worker = withForeignPtr sa (#peek struct sockaddr, sa_family) + worker = withForeignPtr sa (#peek struct sockaddr, sa_family) csas :: (SocketAddress -> IO a) -> [SocketAddress] -> IO a-csas _ [] = fail "No such host"+csas _ [] = throwOther NoSuchHostException csas c [sa] = c sa csas c (sa:sas) = do x <- try' (c sa) case x of@@ -225,6 +233,26 @@ try' :: IO a -> IO (Either SomeException a) try' = E.try +writeOp :: String -> CInt -> IO Int64 -> IO Int64+writeOp desc s op = loop+ where fd = fromIntegral s+ loop = do res <- op+ if res /= -1 then return res else getErrno >>= eh+ eh err | err == eINTR = loop+ | err == eWOULDBLOCK || err == eAGAIN = threadWaitWrite fd >> loop+ | True = throwNetworkException (Socket s) desc err++readOp :: String -> CInt -> IO Int64 -> IO Int64+readOp desc s op = loop+ where fd = fromIntegral s+ loop = do res <- op+ if res /= -1 then return res else getErrno >>= eh+ eh err | err == eINTR = loop+ | err == eWOULDBLOCK || err == eAGAIN = threadWaitRead fd >> loop+ | True = throwNetworkException (Socket s) desc err+++ withResolverLock :: IO a -> IO a #ifdef WINDOWS withResolverLock c = resolverLock `seq` c@@ -236,7 +264,10 @@ withResolverLock x = x #endif -data SocketAddress = SA !(ForeignPtr ()) !Int deriving(Show)+data SocketAddress = SA !(ForeignPtr ()) !Int++instance Show SocketAddress where show _ = "SocketAddress"+ type AddrInfoT = Word8 type CFamily = Int@@ -255,10 +286,10 @@ a2sas t f (IPv4 hn p) = getAddrInfo hn (show p) f afInet t a2sas t f (IPv6 hn p) = getAddrInfo hn (show p) f afInet6 t #ifdef WINDOWS-a2sas _ _ (Unix _) = fail "Unix sockets not supported on Windows"+a2sas _ _ (Unix _) = throwOther UnsupportedAddressFamily #else a2sas _ _ (Unix fp) = do let maxSize = ((#size struct sockaddr_un)-(#offset struct sockaddr_un, sun_path))- when (length fp >= maxSize) $ fail "Too long address for Unix socket"+ when (length fp >= maxSize) $ throwOther AddressTooLongException sa <- mallocForeignPtrBytes $ fromIntegral salLocal withForeignPtr sa $ \sa_ptr -> do (#poke struct sockaddr_un, sun_family) sa_ptr afLocal@@ -267,7 +298,7 @@ pokeArray0 0 ((#ptr struct sockaddr_un, sun_path) sa_ptr) $ map tw fp return [SA sa salLocal] salLocal :: Int-salLocal = #size struct sockaddr_un +salLocal = #size struct sockaddr_un #endif @@ -313,40 +344,13 @@ bracket getAI c_freeaddrinfo unai foreign import CALLCONV unsafe "freeaddrinfo" c_freeaddrinfo :: Ptr AddrInfoT -> IO ()-foreign import CALLCONV safe "getaddrinfo" c_getaddrinfo :: Ptr CChar -> Ptr CChar -> +foreign import CALLCONV safe "getaddrinfo" c_getaddrinfo :: Ptr CChar -> Ptr CChar -> Ptr AddrInfoT -> Ptr (Ptr AddrInfoT) -> IO CInt -throwGAIErrorIf :: IO CInt -> IO ()-throwGAIErrorIf comp = do - err <- comp- when (err /= 0) (gaiError err >>= fail) --- Don't use gai_strerror with winsock - it is not thread-safe there.-gaiError :: CInt -> IO String-#ifdef WINDOWS -gaiError (#const EAI_AGAIN) = return "Temporary failure in name resolution."-gaiError (#const EAI_BADFLAGS) = return "Invalid value for ai_flags."-gaiError (#const EAI_FAIL) = return "Nonrecoverable failure in name resolution."-gaiError (#const EAI_FAMILY) = return "The ai_family member is not supported."-gaiError (#const EAI_MEMORY) = return "Memory allocation failure."-gaiError (#const EAI_NODATA) = return "No address associated with nodename."-gaiError (#const EAI_NONAME) = return "Neither nodename nor servname provided, or not known."-gaiError (#const EAI_SERVICE) = return "The servname parameter is not supported for ai_socktype."-gaiError (#const EAI_SOCKTYPE) = return "The ai_socktype member is not supported."-gaiError x = return ("Unknown gai_error value "++show x)--#else--gaiError err = c_gai_strerror err >>= peekCString--foreign import CALLCONV unsafe "gai_strerror" c_gai_strerror :: CInt -> IO (Ptr CChar)--#endif-- --hostNameToNumber :: Address -> IO [Address] --hostNameToNumber = error "FIXME" --hostNumberToName :: Address -> IO [Address]@@ -356,11 +360,14 @@ getCurrentHost :: IO HostName getCurrentHost = do allocaArray 256 $ \buffer -> do- throwErrnoIfMinus1_ "gethostname" $ c_gethostname buffer 256+ throwIfError_ invSock "gethostname" $ c_gethostname buffer 256 peekCString buffer foreign import CALLCONV unsafe "gethostname" c_gethostname :: Ptr CChar -> CSize -> IO CInt +invSock :: Socket+invSock = Socket (-1)+ -- SERVERS data Threading = Threaded -- ^ Run each request in a separate thread without blocking the server loop.@@ -389,7 +396,7 @@ streamServer :: ServerSpec -> (Handle -> Address -> IO ()) -> IO [ThreadId] streamServer ss sfun = do sas <- a2sas sockStream (aiNumericserv .|. aiPassive) (address ss)- when (null sas) $ fail "No address for server!"+ when (null sas) $ throwOther NoSuchHostException let sf ha psa = case threading ss of Threaded -> forkIO (clo ha $ sfun ha psa) >> return () Inline -> clo ha $ sfun ha psa@@ -398,7 +405,7 @@ False -> id forM sas $ \sa -> do fam <- getFamily sa- sock <- throwErrnoIfMinus1 "socket" $ c_socket fam sockStream 0+ sock <- newsock fam sockStream setNonBlockingFD' sock let socket = Socket sock let on :: CInt@@ -416,18 +423,21 @@ loop forkIO loop +newsock :: CFamily -> CType -> IO CInt+newsock fam typ = throwIfError invSock "socket" $ c_socket fam typ 0+ foreign import CALLCONV unsafe "setsockopt" c_setsockopt :: CInt -> CInt -> CInt -> Ptr a -> CInt -> IO CInt -- | Bind a socket to an address. Be wary of AF_LOCAL + NFS blocking? bind :: Socket -> SocketAddress -> IO ()-bind (Socket sock) (SA sa len) = do- withForeignPtr sa $ \sa_ptr -> - throwErrnoIfMinus1_ "bind" $ c_bind sock sa_ptr (fromIntegral len)+bind s@(Socket fd) (SA sa len) = do+ withForeignPtr sa $ \sa_ptr ->+ throwIfError_ s "bind" $ c_bind fd sa_ptr (fromIntegral len) -- | Listen on an socket listen :: Socket -> Int -> IO ()-listen (Socket s) iv = throwErrnoIfMinus1_ "listen" (c_listen s (toEnum iv))+listen s@(Socket fd) iv = throwIfError_ s "listen" (c_listen fd (toEnum iv)) accept :: Socket -> SocketAddress -> IO (Socket, SocketAddress) accept (Socket lfd) (SA _ len) = do@@ -435,10 +445,10 @@ s <- withForeignPtr sa $ \sa_ptr -> do #ifndef WINDOWS with (fromIntegral len) $ \len_ptr -> do- throwErrnoIfMinus1RetryMayBlock "accept" (c_accept lfd sa_ptr len_ptr) (threadWaitRead (fromIntegral lfd))+ readOp "accept" lfd $ fmap fromIntegral $ c_accept lfd sa_ptr len_ptr #else if threaded then with (fromIntegral len) $ \len_ptr -> do- throwErrnoIfMinus1 "accept" (c_accept lfd sa_ptr len_ptr)+ throwIfError (Socket lfd) "accept" (c_accept lfd sa_ptr len_ptr) else allocaBytes (#size struct network_fancy_aaccept) $ \ptr -> do (#poke struct network_fancy_aaccept, s) ptr lfd (#poke struct network_fancy_aaccept, addr) ptr sa_ptr@@ -446,10 +456,11 @@ r <- asyncDoProc c_nf_async_accept ptr when (r /= 0) $ ioError (errnoToIOError "accept" (Errno (fromIntegral r)) Nothing Nothing) (#peek struct network_fancy_aaccept, s) ptr- + #endif- setNonBlockingFD' s- return (Socket s,SA sa len)+ let s' = fromIntegral s+ setNonBlockingFD' s'+ return (Socket s',SA sa len) foreign import CALLCONV SAFE_ON_WIN "accept" c_accept :: CInt -> Ptr () -> Ptr (SLen) -> IO CInt #ifdef WINDOWS@@ -463,10 +474,10 @@ -> IO [ThreadId] -- ^ ThreadIds of the server listener processes. dgramServer ss sfun = do sas <- a2sas sockDgram (aiNumericserv .|. aiPassive) (address ss)- when (null sas) $ fail "No address for server!"+ when (null sas) $ throwOther NoSuchHostException forM sas $ \sa -> do fam <- getFamily sa- sock <- throwErrnoIfMinus1 "socket" $ c_socket fam sockDgram 0+ sock <- newsock fam sockDgram setNonBlockingFD' sock let socket = Socket sock let on :: CInt@@ -508,10 +519,11 @@ p <- ntohs =<< (#peek struct sockaddr_in6, sin6_port) sa_ptr return $ IPv6 n (fromIntegral p) #ifndef WINDOWS- | f == afLocal-> do n <- peekCString $ (#ptr struct sockaddr_un, sun_path) sa_ptr+ | f == afLocal-> do if len == 0 then return (Unix "") else do+ n <- peekCString $ (#ptr struct sockaddr_un, sun_path) sa_ptr return $ Unix n #endif- | otherwise -> do fail "Unsupported address family!"+ | otherwise -> do throwOther UnsupportedAddressFamilyException foreign import CALLCONV unsafe ntohs :: Word16 -> IO Word16 @@ -532,7 +544,7 @@ | f == afLocal -> do n <- peekCString $ (#ptr struct sockaddr_un, sun_path) sa_ptr return $ Unix n #endif- | otherwise -> do fail "Unsupported address family!"+ | otherwise -> do throwOther UnsupportedAddressFamilyException type SLen = #type socklen_t
+ Network/Fancy/Error.hs view
@@ -0,0 +1,102 @@+-----------------------------------------------------------------------------+--+-- Module : Network.Fancy.Error+-- Copyright : Taru Karttunen <taruti@taruti.net>+-- License : BSD3+--+-- Maintainer : taruti@taruti.net+-- Stability :+-- Portability :+--+-- |+--+-----------------------------------------------------------------------------++module Network.Fancy.Error (+ NetworkException(..),+ throwGAIErrorIf,+ throwIfError,+ throwIfError_,+ throwNetworkException,+ throwOther,+) where++import Control.Exception+import Control.Monad+import Data.Typeable+import Foreign+import Foreign.C+import System.IO.Unsafe++import Network.Fancy.Internal++-- | Exceptions occuring in network-fancy.+data NetworkException = SocketException !String !Socket !Errno+ | GetAdddrInfoException !CInt+ | UnsupportedAddressFamilyException+ | NoSuchHostException+ | AddressTooLongException+ deriving(Typeable)++instance Exception NetworkException++instance Show NetworkException where+ show (SocketException s _ v) = s ++ ": " ++ strerror v+ show (GetAdddrInfoException v) = unsafePerformIO $ gaiError v+ show UnsupportedAddressFamilyException = "Unsupported address family"+ show NoSuchHostException = "No such host"+ show AddressTooLongException = "Network address too long"++throwOther :: NetworkException -> IO any+throwOther x = throwIO $! x++throwIfError_ :: Socket -> String -> IO CInt -> IO ()+throwIfError_ sock desc act = throwIfError sock desc act >> return ()+++throwIfError :: Socket -> String -> IO CInt -> IO CInt+throwIfError sock desc act = do+ res <- act+ when (res == -1) (throwIO . SocketException desc sock =<< getErrno)+ return res++throwNetworkException :: Socket -> String -> Errno -> IO any+throwNetworkException sock desc err = throwIO $! SocketException desc sock err+++strerror :: Errno -> String+strerror (Errno val) = unsafePerformIO $+ allocaArray 512 $ \buffer -> do+ _ <- c_strerror_r val buffer 511+ peekCString buffer++foreign import ccall unsafe "strerror_r" c_strerror_r :: CInt -> Ptr CChar -> CSize -> IO CInt++throwGAIErrorIf :: IO CInt -> IO ()+throwGAIErrorIf comp = do+ err <- comp+ when (err /= 0) $ throwIO $ GetAdddrInfoException err++-- Don't use gai_strerror with winsock - it is not thread-safe there.+gaiError :: CInt -> IO String+#ifdef WINDOWS++gaiError (#const EAI_AGAIN) = return "Temporary failure in name resolution."+gaiError (#const EAI_BADFLAGS) = return "Invalid value for ai_flags."+gaiError (#const EAI_FAIL) = return "Nonrecoverable failure in name resolution."+gaiError (#const EAI_FAMILY) = return "The ai_family member is not supported."+gaiError (#const EAI_MEMORY) = return "Memory allocation failure."+gaiError (#const EAI_NODATA) = return "No address associated with nodename."+gaiError (#const EAI_NONAME) = return "Neither nodename nor servname provided, or not known."+gaiError (#const EAI_SERVICE) = return "The servname parameter is not supported for ai_socktype."+gaiError (#const EAI_SOCKTYPE) = return "The ai_socktype member is not supported."+gaiError x = return ("Unknown gai_error value "++show x)++#else++gaiError err = c_gai_strerror err >>= peekCString++foreign import CALLCONV unsafe "gai_strerror" c_gai_strerror :: CInt -> IO (Ptr CChar)++#endif+
+ Network/Fancy/Internal.hs view
@@ -0,0 +1,23 @@+-----------------------------------------------------------------------------+--+-- Module : Network.Fancy.Internal+-- Copyright : Taru Karttunen <taruti@taruti.net>+-- License : BSD3+--+-- Maintainer : taruti@taruti.net+-- Stability :+-- Portability :+--+-- |+--+-----------------------------------------------------------------------------++module Network.Fancy.Internal (+ Socket(..),+) where+++import Foreign.C++newtype Socket = Socket CInt+
cbits.c view
@@ -26,7 +26,7 @@ #endif-int getSocketError(void) { return errno; }+//int getSocketError(void) { return errno; } int getsockopt_error(int fd) { int estat, res;
+ changelog.md view
@@ -0,0 +1,6 @@+# network-fancy changelog++## Version 0.2.0 2014-12-09++- Use NetworkExceptions for precise error reporting+- Handle unix domain sockets wich don't set SocketAddr on recvFrom
network-fancy.cabal view
@@ -1,34 +1,50 @@-Name: network-fancy-Version: 0.1.5.2-Synopsis: Networking support with a cleaner API-Description: Networking support with a cleaner API-License: BSD3-License-file: COPYING-Copyright: Taru Karttunen <taruti@taruti.net>-Author: Taru Karttunen-Category: Network-Maintainer: taruti@taruti.net-Build-Type: Simple-Cabal-version: >= 1.6-Homepage: http://github.com/taruti/network-fancy-Source-repository head- type: git- location: http://github.com/taruti/network-fancy+name: network-fancy+version: 0.2.0+cabal-version: >=1.6+build-type: Simple+license: BSD3+license-file: COPYING+copyright: Taru Karttunen <taruti@taruti.net>+maintainer: taruti@taruti.net+homepage: http://github.com/taruti/network-fancy+synopsis: Networking support with a cleaner API+description: Networking support with a cleaner API+category: Network+author: Taru Karttunen+data-dir: ""+Extra-Source-Files: changelog.md -Library- Build-Depends: base == 4.*, bytestring- Exposed-modules: Network.Fancy- C-Sources: cbits.c- GHC-Options: -Wall- Extensions: TypeSynonymInstances, ForeignFunctionInterface, CPP, DeriveDataTypeable, FlexibleInstances- if os(windows) {- CPP-Options: -DWINDOWS=WINDOWS -DCALLCONV=stdcall -DSAFE_ON_WIN=safe- CC-Options: -DWINDOWS=WINDOWS -DCALLCONV=stdcall -DSAFE_ON_WIN=safe- Extra-Libraries: ws2_32- } else {- if os(solaris) {- Extra-Libraries: socket- }- CPP-Options: -DCALLCONV=ccall -DSAFE_ON_WIN=unsafe- CC-Options: -DCALLCONV=ccall -DSAFE_ON_WIN=unsafe- }+source-repository head+ type: git+ location: http://github.com/taruti/network-fancy++library+ build-depends: base ==4.*, bytestring -any++ if os(windows)+ exposed: True+ buildable: True+ cpp-options: -DWINDOWS=WINDOWS -DCALLCONV=stdcall+ -DSAFE_ON_WIN=safe+ cc-options: -DWINDOWS=WINDOWS -DCALLCONV=stdcall -DSAFE_ON_WIN=safe+ extra-libraries: ws2_32+ else++ if os(solaris)+ exposed: True+ buildable: True+ extra-libraries: socket+ exposed: True+ buildable: True+ cpp-options: -DCALLCONV=ccall -DSAFE_ON_WIN=unsafe+ cc-options: -DCALLCONV=ccall -DSAFE_ON_WIN=unsafe+ exposed-modules: Network.Fancy+ other-modules: Network.Fancy.Error Network.Fancy.Internal+ exposed: True+ buildable: True+ c-sources: cbits.c+ extensions: TypeSynonymInstances ForeignFunctionInterface CPP+ DeriveDataTypeable FlexibleInstances+ ghc-options: -Wall++