@@ -39,6 +39,9 @@ import Text.Printf
3939
4040import Safe
4141import System.IO (stderr, hPutStrLn)
42+import Foreign.Storable (pokeByteOff, peekByteOff)
43+import Foreign.C (CInt(..))
44+import Foreign.ForeignPtr (withForeignPtr)
4245
4346#ifndef LAZY
4447import Data.ByteString.Char8 (ByteString)
@@ -60,6 +63,9 @@ decode = Ser.decodeLazy
6063encode :: Ser.Serialize a => a -> ByteString
6164decode :: Ser.Serialize a => ByteString -> Either String a
6265
66+foreign import ccall unsafe "htonl" htonl :: CInt -> CInt
67+foreign import ccall unsafe "ntohl" ntohl :: CInt -> CInt
68+
6369type ChanId = Int
6470type Chans = MVar (ChanId, IntMap (Chan [ByteString], [(ThreadId, Socket)]))
6571
@@ -134,11 +140,12 @@ mkSourceEnd host service chanId = withSocketsDo $ do
134140 N.connect sock (addrAddress serverAddr)
135141 NBS.sendAll sock $ encode (fromIntegral chanId :: Int32)
136142 return SourceEnd
137− { send = {-# SCC "send" #-} \bss -> do
138− let size = fromIntegral (sum . map BS.length $ bss) :: Int32
139− sizeStr | size < 255 = BS.singleton (toEnum $ fromEnum size)
140− | otherwise = BS.cons (toEnum 255) (encode size)
141− sendNBS sock (sizeStr:bss)
143+ { send = {-# SCC "send" #-} \bss ->
144+ let size = fromIntegral (sum . map BS.length $ bss) :: Int32 in
145+ if size < 255
146+ then sendNBS sock (BS.singleton (toEnum $ fromEnum size) : bss)
147+ else do size' <- encodeLength size
148+ sendNBS sock (BS.singleton (toEnum 255) : size' : bss)
142149 , closeSourceEnd = {-# SCC "closeSourceEnd" #-} sClose sock
143150 }
144151
@@ -193,15 +200,15 @@ procMessages chans chanId chan sock = do
193200 esizeBS <- recvExact sock 1
194201 case esizeBS of
195202 Left _ -> closeSocket
196− Right sizeBS -> do
197− case decode sizeBS :: Either String Word8 of
198− Right 255 -> do
199− esizeBS' <- recvExact sock (fromIntegral $ sizeOf (0 :: Int32))
200− case esizeBS' of
201− Left _ -> closeSocket
202− Right sizeBS' -> procMessage $ decode sizeBS'
203− esize@(Right _) -> procMessage (fromIntegral <$> esize)
204− Left msg -> error msg
203+ Right sizeBS ->
204+ let size = toEnum . fromEnum $ BS.index sizeBS 0 in
205+ if size < 255
206+ then procMessage size
207+ else do esizeBS' <- recvExact sock (fromIntegral $ sizeOf (0 :: Int32))
208+ case esizeBS' of
209+ Left _ -> closeSocket
210+ Right sizeBS' -> do sizeDec <- decodeLength sizeBS'
211+ procMessage sizeDec
205212 where
206213 err m = error $ printf "procMessages: %s" m
207214 closeSocket :: IO ()
@@ -216,9 +223,8 @@ procMessages chans chanId chan sock = do
216223 let chanMap' = IntMap.insert chanId (chan, socks') chanMap
217224 putMVar chans (chanId', chanMap')
218225 sClose sock
219− procMessage :: Either String Int32 -> IO ()
220− procMessage (Left msg) = err msg
221− procMessage (Right size) = do
226+ procMessage :: Int32 -> IO ()
227+ procMessage size = do
222228 ebs <- recvExact sock size
223229 case ebs of
224230 Left _ -> closeSocket
@@ -289,3 +295,16 @@ forkWithExceptions forkit descr action = do
289295 throwTo parent (e::SomeException)
290296 )
291297
298+-- | Encode length (manual for now)
299+encodeLength :: Int32 -> IO ByteString
300+encodeLength i32 =
301+ BSI.create 4 $ \p ->
302+ pokeByteOff p 0 (htonl (fromIntegral i32))
303+
304+-- | Decode length (manual for now)
305+decodeLength :: ByteString -> IO Int32
306+decodeLength bs =
307+ let (fp, _, _) = BSI.toForeignPtr bs in
308+ withForeignPtr fp $ \p -> do
309+ w32 <- peekByteOff p 0
310+ return (fromIntegral (ntohl w32))