2 haskell comment This module contains some functions that are useful in several places in the
3 haskell comment program and don't belong to one specific other module.
5 haskell code module Gnutella.Misc where
7 haskell code import Data.ByteString(ByteString)
8 haskell code import qualified Data.ByteString as BS
9 haskell code import Data.Bits
10 haskell code import Data.Word
11 haskell code import Text.Read
12 haskell code import Data.Char(isNumber)
13 haskell code import Data.List(intersperse)
14 haskell code import Network
15 haskell code import Network.BSD(getHostByName, HostEntry(..))
16 haskell code import Network.Socket(HostAddress(..))
17 haskell code import Debug.Trace
20 haskell comment Maakt van vier bytes een Word32. Gaat ervan uit dat die vier bytes little-endian achter elkaar
21 haskell comment staan. Als de gegeven string korter is dan 4 bytes, termineert de functie. Als de string langer
22 haskell comment is, worden alle bytes voorbij de vierde genegeerd.
24 haskell code composeWord32 :: ByteString -> Word32
25 haskell code composeWord32 s = shiftL byte4 24 + shiftL byte3 16 + shiftL byte2 8 + byte1
26 haskell code where byte1, byte2, byte3, byte4 :: Word32
27 haskell code [byte1, byte2, byte3, byte4] = map fromIntegral $ BS.unpack (BS.take 4 s)
30 haskell comment Turns a Word32 into a tuple of Word8s. The tuple is little-endian: the least
31 haskell comment significant octet comes first.
33 haskell code word32ToWord8s :: Word32 -> (Word8, Word8, Word8, Word8)
34 haskell code word32ToWord8s w = (fromIntegral (w .&. 0x000000ff)
35 haskell code ,fromIntegral (shiftR w 8 .&. 0x000000ff)
36 haskell code ,fromIntegral (shiftR w 16 .&. 0x000000ff)
37 haskell code ,fromIntegral (shiftR w 24 .&. 0x000000ff)
41 haskell comment Parses a host specification in the "name:12345"-style notation into a hostname
42 haskell comment and a port number.
44 haskell comment As a rather special feature, it returns 6346 as the port number when there is
45 haskell comment no port specified. When there is a port specified, but it is unparseable, it
46 haskell comment returns Nothing.
48 haskell code parseHostnameWithPort :: String -> IO (Maybe ((Word8, Word8, Word8, Word8)
49 haskell code ,PortNumber))
50 haskell code parseHostnameWithPort str = do maybeHostName <- stringToIP hostNameStr
51 haskell code return $ (do portNum <- maybePortNum
52 haskell code hostName <- maybeHostName
53 haskell code return (hostName, portNum)
55 haskell code where hostNameStr = takeWhile (/=':') str
56 haskell code maybePortNum = case tail (dropWhile (/=':') str) of
57 haskell code [] -> Just $ 6346
58 haskell code s -> case reads s of
59 haskell code [] -> Nothing
60 haskell code (x:xs) -> Just $ fromIntegral $ fst x
63 haskell comment Translates a string, representing an IP address, to a list of bytes.
64 haskell comment Returns Nothing when the string does not represent an IP address in xxx.xxx.xxx.xxx format
66 haskell code ipStringToBytes :: String -> Maybe (Word8, Word8, Word8, Word8)
67 haskell comment -- Again, hugs won't let us use regexes where they would be damn convenient
68 haskell code ipStringToBytes s =
69 haskell code let ipBytesStrings = splitAtDots s
70 haskell code in if all (all isNumber) ipBytesStrings
71 haskell code then let bytesList = map (fst . head . reads) ipBytesStrings
72 haskell code in Just (bytesList!!0
73 haskell code ,bytesList!!1
74 haskell code ,bytesList!!2
75 haskell code ,bytesList!!3
77 haskell code else Nothing
78 haskell code where splitAtDots s = foldr (\c (n:nums) -> if c == '.'
79 haskell code then [] : n : nums
80 haskell code else (c:n) : nums
84 haskell comment Translates a list of bytes representing an IP address (big endian) to a string
85 haskell comment in the xxx.xxx.xxx.xxx format.
87 haskell code ipBytesToString :: (Word8, Word8, Word8, Word8) -> String
88 haskell code ipBytesToString (b1, b2, b3, b4) =
89 haskell code concat $ intersperse "." $ map show [b1, b2, b3, b4]
92 haskell comment Takes a String that's either an IP address or a hostname, and returns you the
93 haskell comment IP address as a list of 4 bytes (in big-endian byte order). It returns Nothing
94 haskell comment if there is no parse for the string as IP address and the hostname can't be
95 haskell comment found.
97 haskell code stringToIP :: String -> IO (Maybe (Word8, Word8, Word8, Word8))
98 haskell code stringToIP hostName = case ipStringToBytes hostName of
99 haskell code Just a -> return (Just a)
100 haskell code Nothing -> do hostent <- getHostByName hostName
101 haskell code let ipWord32 = head (hostAddresses hostent)
102 haskell code ipWord8s = word32ToWord8s ipWord32
103 haskell code return (Just ipWord8s)
105 haskell comment -- used in reading the hostcache
106 haskell code instance Read PortNumber where
107 haskell code readsPrec i = map (\(a, b) -> (fromIntegral a, b)) . (readsPrec i :: ReadS Word16)