@@ -1,3 +1,5 @@
1module Network.Transport.TCP
3module Network.Transport.TCP
2 ( mkTransport
4 ( mkTransport
3 , TCPConfig (..)
5 , TCPConfig (..)
@@ -12,19 +14,18 @@ import Control.Concurrent.Chan
12import Control.Concurrent.MVar
14import Control.Concurrent.MVar
13import Control.Monad (forever, forM_)
15import Control.Monad (forever, forM_)
15−import Data.ByteString.Char8 (ByteString)
16−import qualified Data.ByteString.Char8 as BS
17−import Data.ByteString.Internal
17+import qualified Data.ByteString.Internal as BSI
19import Data.IntMap (IntMap)
19import Data.IntMap (IntMap)
20import qualified Data.IntMap as IntMap
20import qualified Data.IntMap as IntMap
22−import Data.Int
22+import Data.Int (Int32)
23−import Data.Serialize
23+import qualified Data.Serialize as Ser
24import Data.Word
24import Data.Word
26import Foreign.ForeignPtr (withForeignPtr)
26import Foreign.ForeignPtr (withForeignPtr)
27import Foreign.Ptr (Ptr, plusPtr)
27import Foreign.Ptr (Ptr, plusPtr)
28+import Foreign.Storable (sizeOf)
29import Network.Socket
30import Network.Socket
30 ( AddrInfoFlag (AI_PASSIVE), HostName, ServiceName, Socket
31 ( AddrInfoFlag (AI_PASSIVE), HostName, ServiceName, Socket
@@ -32,14 +33,30 @@ import Network.Socket
32 , accept, addrAddress, addrFlags, addrFamily, bindSocket, defaultProtocol
33 , accept, addrAddress, addrFlags, addrFamily, bindSocket, defaultProtocol
33 , getAddrInfo, listen, setSocketOption, socket, sClose, withSocketsDo )
34 , getAddrInfo, listen, setSocketOption, socket, sClose, withSocketsDo )
34import qualified Network.Socket as N
35import qualified Network.Socket as N
35−import qualified Network.Socket.ByteString as NBS
37import Text.Printf
37import Text.Printf
39import Safe
39import Safe
41−import qualified Data.Binary as B
41+#ifndef LAZY
42−
42+import Data.ByteString.Char8 (ByteString)
43+import qualified Data.ByteString.Char8 as BS
44+import qualified Network.Socket.ByteString as NBS
45+sendNBS = NBS.sendMany
49+import Data.ByteString.Lazy.Char8 (ByteString)
50+import qualified Data.ByteString.Lazy.Char8 as BS
51+import qualified Network.Socket.ByteString.Lazy as NBS
52+sendNBS sock bs = NBS.sendAll sock $! head bs
53+encode = Ser.encodeLazy
54+decode = Ser.decodeLazy
58+encode :: Ser.Serialize a => a -> ByteString
59+decode :: Ser.Serialize a => ByteString -> Either String a
44type ChanId = Int
61type ChanId = Int
45type Chans = MVar (ChanId, IntMap (Chan [ByteString], [(ThreadId, Socket)]))
62type Chans = MVar (ChanId, IntMap (Chan [ByteString], [(ThreadId, Socket)]))
@@ -112,13 +129,13 @@ mkSourceEnd host service chanId = withSocketsDo $ do
112 sock <- socket (addrFamily serverAddr) Stream defaultProtocol
129 sock <- socket (addrFamily serverAddr) Stream defaultProtocol
113 setSocketOption sock ReuseAddr 1
130 setSocketOption sock ReuseAddr 1
114 N.connect sock (addrAddress serverAddr)
131 N.connect sock (addrAddress serverAddr)
115− NBS.sendAll sock $ encode (fromIntegral chanId :: Int64)
132+ NBS.sendAll sock $ encode (fromIntegral chanId :: Int32)
116 return SourceEnd
133 return SourceEnd
117 { send = {-# SCC "send" #-} \bss -> do
134 { send = {-# SCC "send" #-} \bss -> do
118− let size = fromIntegral (sum . map BS.length $ bss) :: Int64
135+ let size = fromIntegral (sum . map BS.length $ bss) :: Int32
119 sizeStr | size < 255 = encode (fromIntegral size :: Word8)
136 sizeStr | size < 255 = encode (fromIntegral size :: Word8)
120 | otherwise = BS.cons (toEnum 255) (encode size)
137 | otherwise = BS.cons (toEnum 255) (encode size)
121− NBS.sendMany sock (sizeStr:bss)
138+ sendNBS sock (sizeStr:bss)
122 , closeSourceEnd = {-# SCC "closeSourceEnd" #-} sClose sock
139 , closeSourceEnd = {-# SCC "closeSourceEnd" #-} sClose sock
@@ -145,11 +162,11 @@ procConnections chans sock = forever $ do
145 let err m = error $ printf "procConnections: %s" m
162 let err m = error $ printf "procConnections: %s" m
146 (clientSock, _clientAddr) <- accept sock
163 (clientSock, _clientAddr) <- accept sock
147 -- decode the first message to find the correct chanId
164 -- decode the first message to find the correct chanId
148− bss <- recvExact clientSock 8
165+ bss <- recvExact clientSock (fromIntegral $ sizeOf (0 :: Int32))
149 case bss of
166 case bss of
150 Left _ -> err "inbound chanId aborted"
167 Left _ -> err "inbound chanId aborted"
151 Right bs -> do
168 Right bs -> do
152− let chanId = either err fromIntegral (decode bs :: Either String Int64)
169+ let chanId = either err fromIntegral (decode bs :: Either String Int32)
153 (chanId', chanMap) <- takeMVar chans
170 (chanId', chanMap) <- takeMVar chans
154 case IntMap.lookup chanId chanMap of
171 case IntMap.lookup chanId chanMap of
155 Nothing -> do
172 Nothing -> do
@@ -175,7 +192,7 @@ procMessages chans chanId chan sock = do
175 Right sizeBS -> do
192 Right sizeBS -> do
176 case decode sizeBS :: Either String Word8 of
193 case decode sizeBS :: Either String Word8 of
177 Right 255 -> do
194 Right 255 -> do
178− esizeBS' <- recvExact sock 8
195+ esizeBS' <- recvExact sock (fromIntegral $ sizeOf (0 :: Int32))
179 case esizeBS' of
196 case esizeBS' of
180 Left _ -> closeSocket
197 Left _ -> closeSocket
181 Right sizeBS' -> procMessage $ decode sizeBS'
198 Right sizeBS' -> procMessage $ decode sizeBS'
@@ -194,7 +211,7 @@ procMessages chans chanId chan sock = do
194 let chanMap' = IntMap.insert chanId (chan, socks') chanMap
211 let chanMap' = IntMap.insert chanId (chan, socks') chanMap
195 putMVar chans (chanId', chanMap')
212 putMVar chans (chanId', chanMap')
196 sClose sock
213 sClose sock
197− procMessage :: Either String Int64 -> IO ()
214+ procMessage :: Either String Int32 -> IO ()
198 procMessage (Left msg) = err msg
215 procMessage (Left msg) = err msg
199 procMessage (Right size) = do
216 procMessage (Right size) = do
200 ebs <- recvExact sock size
217 ebs <- recvExact sock size
@@ -216,22 +233,33 @@ procMessages chans chanId chan sock = do
216-- a partial retrieval since the socket was closed, and `return Right bs`
233-- a partial retrieval since the socket was closed, and `return Right bs`
217-- indicates success. This hasn't been implemented, since a Transport `receive`
234-- indicates success. This hasn't been implemented, since a Transport `receive`
218-- represents an atomic receipt of a message.
235-- represents an atomic receipt of a message.
219−recvExact :: Socket -> Int64 -> IO (Either ByteString ByteString)
237+recvExact :: Socket -> Int32 -> IO (Either ByteString ByteString)
220recvExact sock l = do
238recvExact sock l = do
221− res <- createAndTrim (fromIntegral l) (go 0)
239+ res <- BSI.createAndTrim (fromIntegral l) (go 0)
222 case BS.length res of
240 case BS.length res of
223 n | n == (fromIntegral l) -> return $ Right res
241 n | n == (fromIntegral l) -> return $ Right res
225− printf "recvExact: expected %dB, got %dB\n" l n
226− return $ Left res
242+ n -> return $ Left res
228 go :: Int -> Ptr Word8 -> IO Int
244 go :: Int -> Ptr Word8 -> IO Int
229 go n ptr | n == (fromIntegral l) = return n
245 go n ptr | n == (fromIntegral l) = return n
230 go n ptr = do
246 go n ptr = do
231− (p, off, len) <- toForeignPtr <$> NBS.recv sock (fromIntegral l)
247+ (p, off, len) <- BSI.toForeignPtr <$> NBS.recv sock (min (fromIntegral l-n) 4096)
232 if len == 0
248 if len == 0
233 then return n
249 then return n
234 else withForeignPtr p $ \p -> do
250 else withForeignPtr p $ \p -> do
235− memcpy (ptr `plusPtr` n) (p `plusPtr` off) (fromIntegral len)
251+ BSI.memcpy (ptr `plusPtr` n) (p `plusPtr` off) (fromIntegral len)
236 go (n+len) ptr
252 go (n+len) ptr
254+recvExact :: Socket -> Int32 -> IO (Either ByteString ByteString)
258+ go :: [ByteString] -> Socket -> Int32 -> IO (Either ByteString ByteString)
259+ go bss _ 0 = return (Right $ BS.concat (reverse bss))
261+ bs <- NBS.recv sock (min (fromIntegral n) 4096)
263+ then return (Left $ BS.concat (reverse bss))
264+ else go (bs:bss) sock (n - (fromIntegral $ BS.length bs))