packages feed

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 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++