diff options
author | Joe Crayne <joe@jerkface.net> | 2019-12-29 03:32:37 -0500 |
---|---|---|
committer | Joe Crayne <joe@jerkface.net> | 2020-01-03 17:26:06 -0500 |
commit | b69fd50df8ec24733cef44cb5772fea69cc1e511 (patch) | |
tree | b9bf4ac9effa5c6a2a923b2a92cc674e8f958770 | |
parent | f37cd8aa9134142d6a23156fc4fd0c6cb5a308dd (diff) |
readnodes.hs: Utility to write nodes in a binary format.
-rw-r--r-- | dht/examples/readnodes.hs | 96 |
1 files changed, 96 insertions, 0 deletions
diff --git a/dht/examples/readnodes.hs b/dht/examples/readnodes.hs new file mode 100644 index 00000000..e4a5b522 --- /dev/null +++ b/dht/examples/readnodes.hs | |||
@@ -0,0 +1,96 @@ | |||
1 | import Control.Monad | ||
2 | import qualified Data.ByteArray as BA | ||
3 | import Data.ByteString (hPutStr,pack) | ||
4 | import Data.Char | ||
5 | import Data.Function | ||
6 | import Data.Int | ||
7 | import Data.List | ||
8 | import Data.Maybe | ||
9 | import Data.Word | ||
10 | import Foreign.Ptr | ||
11 | import Foreign.Marshal.Utils | ||
12 | import Foreign.Storable | ||
13 | import Network.Tox.NodeId | ||
14 | import System.Environment | ||
15 | import System.IO (stdout) | ||
16 | import Text.Read | ||
17 | |||
18 | -- struct bootstrap_node { | ||
19 | -- 8 char *address; | ||
20 | -- 2 bool ipv6; | ||
21 | -- 2 uint16_t port_udp; | ||
22 | -- 2 uint16_t port_tcp; | ||
23 | -- 32 uint8_t key[32]; | ||
24 | -- 2 | ||
25 | -- } bootstrap_nodes[] = { | ||
26 | |||
27 | |||
28 | int32_bytes :: Int32 -> IO [Word8] | ||
29 | int32_bytes = int_bytes | ||
30 | |||
31 | int16_bytes :: Int16 -> IO [Word8] | ||
32 | int16_bytes i = int_bytes i | ||
33 | |||
34 | int_bytes :: Storable a => a -> IO [Word8] | ||
35 | int_bytes i = with i $ \p0 -> | ||
36 | let p = castPtr p0 | ||
37 | in foldr (\g r -> g >>= \x -> fmap (x :) r) (return []) | ||
38 | $ peekElemOff p `map` [ 0 .. sizeOf i - 1 ] | ||
39 | |||
40 | |||
41 | node_bytes :: Int32 -> Int -> String -> NodeInfo -> IO [Word8] | ||
42 | node_bytes num_nodes a s n = do | ||
43 | -- amd64 8 + 2 + 2 + 2 + 32 + 2 = 48 | ||
44 | -- sizeof(bootstrap_node) = 48 | ||
45 | -- i386 4 + 2 + 2 + 2 + 32 + 2 = 44 | ||
46 | -- sizeof(bootstrap_node) = 44 | ||
47 | bigendian <- (==0) . head <$> int32_bytes 1 | ||
48 | let sz = sizeOf (0::Int) + 2 + 2 + 2 + 32 + 2 | ||
49 | base = fromIntegral num_nodes * sz | ||
50 | ip6 = case find (==':') s of | ||
51 | Just _ | bigendian -> [0,1] | ||
52 | | otherwise -> [1,0] | ||
53 | _ -> [0,0] | ||
54 | t = [0,0] -- TODO: TCP port | ||
55 | nid = nodeId n | ||
56 | adr <- int_bytes (base + a) | ||
57 | u <- int16_bytes $ fromIntegral $ nodePort n | ||
58 | return $ foldr (++) [] | ||
59 | [ adr -- char *address; | ||
60 | , ip6 -- bool ipv6; | ||
61 | , u -- uint16_t port_udp | ||
62 | , t -- uint16_t port_tcp | ||
63 | , BA.unpack (id2key nid) -- uint8_t key[32]; | ||
64 | , [0,0] -- padding | ||
65 | ] | ||
66 | |||
67 | addressString :: NodeInfo -> String | ||
68 | addressString ni = case show (nodeAddr ni) of | ||
69 | '[':xs -> takeWhile (/=']') xs | ||
70 | xs -> takeWhile (/=':') xs | ||
71 | where | ||
72 | a = show (nodeAddr ni) | ||
73 | |||
74 | main = do | ||
75 | args <- getArgs | ||
76 | let [ifilename] = args | ||
77 | ws <- words <$> readFile ifilename | ||
78 | let ns :: [ NodeInfo ] | ||
79 | ns = mapMaybe readMaybe ws | ||
80 | num_nodes :: Int32 | ||
81 | num_nodes = fromIntegral $ length ns | ||
82 | ptr_size :: Int32 | ||
83 | ptr_size = fromIntegral $ sizeOf (0 :: Int) | ||
84 | ss = map addressString ns | ||
85 | as = scanl (\i a -> length a + i + 1) 0 ss | ||
86 | let h = stdout | ||
87 | nbs <- int32_bytes num_nodes | ||
88 | pbs <- int32_bytes ptr_size | ||
89 | hPutStr h $ pack $ nbs ++ pbs | ||
90 | forM_ (zip3 as ss ns) $ \(a,s,n) -> do | ||
91 | bs <- node_bytes num_nodes a s n | ||
92 | hPutStr h $ pack bs | ||
93 | hPutStr h $ pack $ do | ||
94 | adr <- ss | ||
95 | map (fromIntegral . ord) adr ++ [0] | ||
96 | |||