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
97
98
99
100
|
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 System.Environment
import System.IO (stdout)
import Text.Read
import qualified Network.Tox.NodeId as UDP
import Network.Tox.TCP.NodeId as TCP
-- 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]
nid = UDP.nodeId $ udpNodeInfo n
adr <- int_bytes (base + a)
u <- int16_bytes $ fromIntegral $ UDP.nodePort $ udpNodeInfo n
t <- int16_bytes $ fromIntegral $ tcpPort n
return $ foldr (++) []
[ adr -- char *address;
, ip6 -- bool ipv6;
, u -- uint16_t port_udp
, t -- uint16_t port_tcp
, BA.unpack (UDP.id2key nid) -- uint8_t key[32];
, [0,0] -- padding
]
addressString :: NodeInfo -> String
addressString ni = case show (UDP.nodeAddr $ udpNodeInfo ni) of
'[':xs -> takeWhile (/=']') xs
xs -> takeWhile (/=':') xs
readNode :: String -> Maybe NodeInfo
readNode nstr = mplus (readMaybe nstr)
(fromUDPNode <$> readMaybe nstr)
main = do
args <- getArgs
let [ifilename] = args
ws <- words <$> readFile ifilename
let ns :: [ NodeInfo ]
ns = mapMaybe readNode 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]
|