network-bytestring (empty) → 0.1
raw patch · 4 files changed
+258/−0 lines, 4 filesdep +HUnitdep +basedep +bytestringbuild-type:Customsetup-changed
Dependencies added: HUnit, base, bytestring, network
Files
- LICENSE +31/−0
- Network/Socket/ByteString.cpphs +210/−0
- Setup.lhs +3/−0
- network-bytestring.cabal +14/−0
+ LICENSE view
@@ -0,0 +1,31 @@+Copyright Johan Tibell 2007++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++ * Redistributions of source code must retain the above copyright+ notice, this list of conditions and the following disclaimer.++ * Redistributions in binary form must reproduce the above+ copyright notice, this list of conditions and the following+ disclaimer in the documentation and/or other materials provided+ with the distribution.++ * Neither the name of Johan Tibell nor the names of other+ contributors may be used to endorse or promote products derived+ from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.+
+ Network/Socket/ByteString.cpphs view
@@ -0,0 +1,210 @@+{-# OPTIONS_GHC -cpp #-}++-- |+-- Module : Network.Socket.ByteString+-- Copyright : (c) Johan Tibell 2007+-- License : BSD-style+--+-- Maintainer : johan.tibell@gmail.com+-- Stability : experimental+-- Portability : portable+--+-- | A module for efficiently transmitting data over sockets. For+-- detailed documentation consult your favorite POSIX socket+-- reference. All functions communicate failures by converting the+-- error number to an 'System.IO.IOError'.+--+-- This module is intended to be imported together with 'Network.Socket' like so:+--+-- > import Network.Socket hiding (send, sendTo, recv, recvFrom)+-- > import Network.Socket.ByteString+--+module Network.Socket.ByteString+ (+ -- * Send a message on a socket+ -- | Functions used to transmit a message to another socket.+ send,+ sendTo,++ -- * Receive a message from a socket+ -- | Functions used to receive messages from a socket, and may be+ -- used to receive data on a socket whether or not it is+ -- connection-oriented.+ recv,+ recvFrom+ ) where++import Control.Monad (liftM)+import Data.ByteString (ByteString)+import qualified Data.ByteString as B+import Data.ByteString.Internal (create)+import Data.ByteString.Unsafe (unsafeUseAsCStringLen)+import Foreign.C.Error+import Foreign.C.Types (CChar, CInt, CSize)+import Foreign.Marshal.Alloc (allocaBytes)+import Foreign.Ptr (Ptr, castPtr)+import Network.Socket (SockAddr, Socket(..), sendBufTo, recvBufFrom)++#if defined(__GLASGOW_HASKELL__)+import GHC.Conc (threadWaitRead, threadWaitWrite)+import GHC.IOBase (IOErrorType(..), IOException(..))+# if defined(mingw32_HOST_OS)+import GHC.Handle (readRawBufferPtr, writeRawBufferPtr)+# endif+#else+import System.IO.Unsafe (unsafePerformIO)+#endif++#ifndef CALLCONV+# ifdef WITH_WINSOCK+# define CALLCONV stdcall+# else+# define CALLCONV ccall+# endif+#endif+foreign import CALLCONV unsafe "send"+ c_send :: CInt -> Ptr a -> CSize -> CInt -> IO CInt+foreign import CALLCONV unsafe "recv"+ c_recv :: CInt -> Ptr CChar -> CSize -> CInt -> IO CInt++-- -----------------------------------------------------------------------------+-- Sending++-- | Transmit a message to another socket. The socket must be in a+-- connected state so that the intended recipient is known.+send :: Socket -- ^ Bound\/Connected socket.+ -> ByteString -- ^ Data to send.+ -> IO Int -- ^ Number of bytes sent.+send (MkSocket s _family _stype _protocol status) xs = do+ unsafeUseAsCStringLen xs $ \(str, len) -> do+ liftM fromIntegral $+#if defined(__GLASGOW_HASKELL__) && defined(mingw32_HOST_OS)+ writeRawBufferPtr "Network.Socket.ByteString.send" (fromIntegral s) True str 0+ (fromIntegral len)+#else+# if !defined(__HUGS__)+ throwErrnoIfMinus1Retry_repeatOnBlock "send"+ (threadWaitWrite (fromIntegral s)) $+# endif+ c_send s str (fromIntegral len) 0{-flags-}+#endif++-- | Transmit a message to another socket. The recipient can be+-- specified explicitly so the socket must not (but can be) in a+-- connected state.+sendTo :: Socket -- ^ (Possibly) bound\/connected 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++-- -----------------------------------------------------------------------------+-- Receiving++-- | Receive a message from another socket. The socket must be in a+-- connected state so that the intended recipient is known. Note that+-- the length of the received data can be smaller than specified+-- maximum length. If the message is longer than the specified length+-- it may be discarded depending on the type of socket. May block+-- until a message arrives.+recv :: Socket -- ^ Bound\/connected socket.+ -> Int -- Maximum number of bytes to receive.+ -> IO ByteString -- Data received.+recv sock@(MkSocket s _ _ _ _) nbytes+ | nbytes <= 0 = ioError (mkInvalidRecvArgError "Network.Socket.ByteString.recv")+ | otherwise = do+ create nbytes $ \ptr -> do+ len <-+#if defined(__GLASGOW_HASKELL__) && defined(mingw32_HOST_OS)+ readRawBufferPtr "Network.Socket.ByteString.recvLen" (fromIntegral s) True+ (castPtr ptr) 0 (fromIntegral nbytes)+#else+# if !defined(__HUGS__)+ throwErrnoIfMinus1Retry_repeatOnBlock "recv"+ (threadWaitRead (fromIntegral s)) $+# endif+ c_recv s (castPtr ptr) (fromIntegral nbytes) 0{-flags-}+#endif+ if fromIntegral len == 0+ then ioError (mkEOFError "Network.Socket.ByteString.recv")+ else return ()++-- | Similar to 'recv' but can be used to receive data on a socket+-- that is not connection-oriented.+recvFrom :: Socket -- ^ (Possibly) bound\/connected 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)++mkInvalidRecvArgError :: String -> IOError+mkInvalidRecvArgError loc = IOError Nothing+#ifdef __GLASGOW_HASKELL__+ InvalidArgument+#else+ IllegalOperation+#endif+ loc "non-positive length" Nothing++mkEOFError :: String -> IOError+mkEOFError loc = IOError Nothing EOF loc "end of file" Nothing++-----------------------------------------------------------------------------+-- Support for thread-safe blocking operations in GHC.++#if defined(__GLASGOW_HASKELL__) && !(defined(HAVE_WINSOCK_H) && !defined(cygwin32_HOST_OS))+{-# SPECIALISE+ throwErrnoIfMinus1Retry_mayBlock+ :: String -> IO CInt -> IO CInt -> IO CInt #-}+throwErrnoIfMinus1Retry_mayBlock :: Num a => String -> IO a -> IO a -> IO a+throwErrnoIfMinus1Retry_mayBlock name on_block act = do+ res <- act+ if res == -1+ then do+ err <- getErrno+ if err == eINTR+ then throwErrnoIfMinus1Retry_mayBlock name on_block act+ else if err == eWOULDBLOCK || err == eAGAIN+ then on_block+ else throwErrno name+ else return res++throwErrnoIfMinus1Retry_repeatOnBlock :: Num a => String -> IO b -> IO a -> IO a+throwErrnoIfMinus1Retry_repeatOnBlock name on_block act = do+ throwErrnoIfMinus1Retry_mayBlock name (on_block >> repeat) act+ where repeat = throwErrnoIfMinus1Retry_repeatOnBlock name on_block act++#else+throwErrnoIfMinus1Retry_mayBlock name _ act+ = throwSocketErrorIfMinus1Retry name act++throwErrnoIfMinus1Retry_repeatOnBlock name _ act+ = throwSocketErrorIfMinus1Retry name act++# if defined(HAVE_WINSOCK_H) && !defined(cygwin32_HOST_OS)+throwSocketErrorIfMinus1Retry name act = do+ r <- act+ if (r == -1)+ then do+ rc <- c_getLastError+ case rc of+ 10093 -> do -- WSANOTINITIALISED+ withSocketsDo (return ())+ r <- act+ if (r == -1)+ then (c_getLastError >>= throwSocketError name)+ else return r+ _ -> throwSocketError name rc+ else return r++foreign import CALLCONV unsafe "WSAGetLastError"+ c_getLastError :: IO CInt++# else+throwSocketErrorIfMinus1Retry name act = throwErrnoIfMinus1Retry name act+# endif+#endif /* __GLASGOW_HASKELL */
+ Setup.lhs view
@@ -0,0 +1,3 @@+#!/usr/bin/env runhaskell+> import Distribution.Simple+> main = defaultMain
+ network-bytestring.cabal view
@@ -0,0 +1,14 @@+name: network-bytestring+version: 0.1+synopsis: Fast and memory efficient low-level networking+description: Faster and more memory efficient low-level socket functions using+ 'Data.ByteString's instead of 'String's.+license: BSD3+license-file: LICENSE+author: Johan Tibell+maintainer: johan.tibell@gmail.com+category: Network+build-depends: base, bytestring, HUnit, network+ghc-options: -O+exposed-modules: Network.Socket.ByteString+extensions: CPP, ForeignFunctionInterface