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