darcs patch: Implementation of aton and ntoa outside ... (and
1 more)
Simon Marlow
simonmarhaskell at gmail.com
Tue Nov 14 05:52:07 EST 2006
Robert: would you like to resubmit this suggestion using the new submission
guidelines for library additions?
http://www.haskell.org/haskellwiki/Library_submissions
Cheers,
Simon
Robert Marlow wrote:
> On Fri, 2006-09-29 at 13:19 +0100, Simon Marlow wrote:
>
>>inet_ntoa() uses a static buffer, so it isn't threadsafe. So while the current
>>IO version is already broken, putting unsafePerformIO around it makes the
>>problem more likely to manifest, and harder to avoid. We really need to do this
>>in Haskell code, I think.
>
>
> I've attached a new revision of the earlier Data.Byte module I sent to
> this list.
>
> I've taken Bulat's suggestion on making flipEndian more efficient and
> extended it so it should work with all word sizes as well as signed
> types such as Ints.
>
> The file also includes purely functional versions of aton and ntoa,
> though a module named Data.Byte is the wrong place for them.
>
> One problem is that aton and ntoa currently only work with ipv4
> addresses. There should probably be versions for ipv6 and any others.
> This doesn't seem to be a problem the current inet_addr and inet_ntoa
> don't suffer from though.
>
> A lot of the functions don't work with Integers due to a use of bitSize.
>
>
>
>
> ------------------------------------------------------------------------
>
> module Data.Byte
> ( ByteOrder (..)
> , hostByteOrder
> , networkByteOrder
> , changeByteOrder
> , hton
> , ntoh
>
> , byteShow
> , byteRead
> , word8ToChar
> , charToWord8
> , showBits
>
> , logShift
> , logShiftL
> , logShiftR
>
> , flipEndian
>
> , word8Split
> , word8Concat
>
> , aton
> , ntoa )
> where
>
>
> import Control.Exception
>
> import Data.Bits
> import Data.Char
> import Data.List
> import Data.Word
>
> import Network.Socket
>
> import System.Info
> import System.IO.Unsafe
>
> import Foreign.Marshal.Utils ( with )
> import Foreign.Storable ( peekByteOff )
>
> import Text.Regex
>
>
> data ByteOrder = BigEndian | LittleEndian
> deriving ( Eq, Show, Read )
>
>
> hostByteOrder :: ByteOrder
> hostByteOrder = let test = (word8Concat [1,2]) :: Word16
> answer = (unsafePerformIO $ with test firstByte) :: Word8 in
> case answer of
> 1 -> LittleEndian
> 2 -> BigEndian
> otherwise -> throw $ ErrorCall $ "Unexpected result when checking byte order"
> where firstByte = (flip peekByteOff) 0
>
> networkByteOrder :: ByteOrder
> networkByteOrder = BigEndian
>
>
> changeByteOrder :: (Bits a, Integral a) => ByteOrder -> ByteOrder -> a -> a
> changeByteOrder bo1 bo2 x = if bo1 == bo2
> then x
> else flipEndian x
>
>
> -- |Host to Network byteorder
> hton :: (Bits a, Integral a) => a -> a
> hton = changeByteOrder hostByteOrder networkByteOrder
>
> -- |Network to Host byteorder
> ntoh :: (Bits a, Integral a) => a -> a
> ntoh = hton
>
>
> -- |Converts the argument to a string representing the bytes in the
> -- argument
> byteShow :: (Integral a, Bits a) => a -> String
> byteShow = (map word8ToChar) . word8Split
>
> -- |Reads a string of bytes. Reads only as many bytes as are needed
> -- to represent the resulting type. Does not work with Integers
> byteRead :: (Bits a, Integral a) => String -> a
> byteRead = word8Concat . (map charToWord8)
>
> word8ToChar :: Word8 -> Char
> word8ToChar = chr . fromEnum
>
> charToWord8 :: Char -> Word8
> charToWord8 = toEnum . ord
>
> -- |Returns a string representing the bits of the argument.
> -- Does not work with Integers
> showBits :: Bits a => a -> String
> showBits x = showBits' ((bitSize x) -1) x
> where showBits' i x | i < 0 = ""
> | testBit x i = '1' : showBits' (i-1) x
> | otherwise = '0' : showBits' (i-1) x
>
>
> -- |Reverses the endianness of the argument. Does not work
> -- with Integers
> flipEndian :: Bits a => a -> a
> flipEndian x = bwOr $ zipWith logShift bytes shiftLengths
> where bytes = map (x .&.) $ map (shift 255) [0,8..sz-8]
> shiftLengths = [sz-8,sz-24..(negate sz)+8]
> sz = bitSize x
>
> -- flipEndian = word8Concat . reverse . word8Split
>
> bwOr :: Bits a => [a] -> a
> bwOr = foldr (.|.) 0
>
>
> -- |Logical shift version of the shift operator. Does not work with
> -- Integers
> logShift :: Bits a => a -> Int -> a
> logShift x i | i >= 0 = logShiftL x i
> | otherwise = logShiftR x i
>
> -- |Logical shift version of the shiftR operator. Does not work with
> -- Integers
> logShiftR :: Bits a => a -> Int -> a
> logShiftR x i | isSigned x = clearBits (shiftR x i) (sz+i) sz
> | otherwise = shiftR x i
> where sz = bitSize x
>
> -- |Identical to the shiftL operator.
> logShiftL :: Bits a => a -> Int -> a
> logShiftL = shiftL
>
>
> clearBits :: Bits a => a -> Int -> Int -> a
> clearBits x min max | min >= max = x
> | otherwise = clearBits (clearBit x min) (min+1) max
>
>
> -- |Returns a list of Word8s in little-endian byte order. Does not
> -- work with Integers
> word8Split :: (Integral a, Bits a) => a -> [Word8]
> word8Split x = map (fromIntegral . (shiftR x)) [0,8..sz-8]
> where sz = bitSize x
>
> -- |Concats a list of Word8s in little-endian byte order.
> -- For big-endian byte order reverse the Word8s first.
> -- Does not work with Integers
> word8Concat :: (Bits a, Integral a) => [Word8] -> a
> word8Concat w8s = bwOr $ zipWith shiftL xs [0,8..sz-8]
> where xs = map fromIntegral w8s
> sz = bitSize $ head xs
>
>
> -- |Implementation of inet_addr outside the IO monad
> aton :: String -> HostAddress
> aton ipstr = word8Concat $ toBytes ipstr
> where toBytes = (map readByte) . checkLength . dotSplit
> dotSplit = splitRegex $ mkRegex "\\."
> checkLength x = if length x == 4 then x else malformed
> readByte b = case reads b of
> ((x,""):_) -> if x >= 0 && x <= 255
> then fromInteger x
> else malformed
> otherwise -> malformed
> malformed = throw $ ErrorCall $ "Malformed Address: " ++ ipstr
>
>
> -- |Implementation of inet_ntoa outside the IO monad
> ntoa :: HostAddress -> String
> ntoa = concat . (intersperse ".") . (map show) . word8Split
>
>
>
> ------------------------------------------------------------------------
>
> _______________________________________________
> Libraries mailing list
> Libraries at haskell.org
> http://www.haskell.org/mailman/listinfo/libraries
More information about the Libraries
mailing list