diff options
Diffstat (limited to 'dht/src/Network/Tox/TCP/NodeId.hs')
-rw-r--r-- | dht/src/Network/Tox/TCP/NodeId.hs | 89 |
1 files changed, 89 insertions, 0 deletions
diff --git a/dht/src/Network/Tox/TCP/NodeId.hs b/dht/src/Network/Tox/TCP/NodeId.hs new file mode 100644 index 00000000..c218c88f --- /dev/null +++ b/dht/src/Network/Tox/TCP/NodeId.hs | |||
@@ -0,0 +1,89 @@ | |||
1 | {-# LANGUAGE CPP #-} | ||
2 | module Network.Tox.TCP.NodeId where | ||
3 | |||
4 | import Crypto.Tox | ||
5 | import qualified Network.Tox.NodeId as UDP | ||
6 | |||
7 | import qualified Data.Aeson as JSON | ||
8 | ;import Data.Aeson (FromJSON (..), ToJSON (..)) | ||
9 | import Data.Functor.Contravariant | ||
10 | import Data.Hashable | ||
11 | import qualified Data.HashMap.Strict as HashMap | ||
12 | import qualified Data.Vector as Vector | ||
13 | import Data.Word | ||
14 | import Network.Socket | ||
15 | import qualified Text.ParserCombinators.ReadP as RP | ||
16 | import Data.Serialize as S | ||
17 | |||
18 | #if MIN_VERSION_iproute(1,7,4) | ||
19 | import Data.IP hiding (fromSockAddr) | ||
20 | #else | ||
21 | import Data.IP | ||
22 | #endif | ||
23 | |||
24 | data NodeInfo = NodeInfo | ||
25 | { udpNodeInfo :: UDP.NodeInfo | ||
26 | , tcpPort :: PortNumber | ||
27 | } | ||
28 | deriving (Eq,Ord) | ||
29 | |||
30 | instance Read NodeInfo where | ||
31 | readsPrec _ = RP.readP_to_S $ do | ||
32 | udp <- RP.readS_to_P reads | ||
33 | port <- RP.between (RP.char '{') (RP.char '}') $ do | ||
34 | mapM_ RP.char ("tcp:" :: String) | ||
35 | w16 <- RP.readS_to_P reads | ||
36 | return $ fromIntegral (w16 :: Word16) | ||
37 | return $ NodeInfo udp port | ||
38 | |||
39 | instance ToJSON NodeInfo where | ||
40 | toJSON (NodeInfo udp port) = case (toJSON udp) of | ||
41 | JSON.Object tbl -> JSON.Object $ HashMap.insert "tcp_ports" | ||
42 | (JSON.Array $ Vector.fromList | ||
43 | [JSON.Number (fromIntegral port)]) | ||
44 | tbl | ||
45 | x -> x -- Shouldn't happen. | ||
46 | |||
47 | -- example: | ||
48 | -- KEyW2Bm.S-DpIGp72380BAfgintUWX1KX.6ZU.4m5Ex@80.99.99.99:33400{tcp:443} | ||
49 | instance Show NodeInfo where | ||
50 | show (NodeInfo udp port) = show udp ++ "{tcp:"++show port++"}" | ||
51 | |||
52 | instance Sized NodeInfo where | ||
53 | size = contramap udpNodeInfo size | ||
54 | |||
55 | |||
56 | getIP :: Word8 -> S.Get (Bool, IP) | ||
57 | getIP 0x02 = (,) False . IPv4 <$> S.get -- UDP 4 | ||
58 | getIP 0x0a = (,) False . IPv6 <$> S.get -- UDP 6 | ||
59 | getIP 0x82 = (,) True . IPv4 <$> S.get -- TCP 4 | ||
60 | getIP 0x8a = (,) True . IPv6 <$> S.get -- TCP 6 | ||
61 | getIP x = fail ("unsupported address family ("++show x++")") | ||
62 | |||
63 | instance S.Serialize NodeInfo where | ||
64 | get = do | ||
65 | addrfam <- S.get :: S.Get Word8 | ||
66 | (istcp, ip) <- getIP addrfam | ||
67 | port <- S.get :: S.Get PortNumber | ||
68 | nid <- S.get | ||
69 | let (udpport, tcpport) = if istcp | ||
70 | then (0, port) | ||
71 | else (port, 0) | ||
72 | return $ NodeInfo (UDP.NodeInfo nid ip udpport) tcpport | ||
73 | |||
74 | put (NodeInfo (UDP.NodeInfo nid ip udpport) tcpport) = do | ||
75 | if tcpport==0 | ||
76 | then do | ||
77 | case ip of | ||
78 | IPv4 ip4 -> S.put (2 :: Word8) >> S.put ip4 | ||
79 | IPv6 ip6 -> S.put (10 :: Word8) >> S.put ip6 | ||
80 | S.put udpport | ||
81 | else do | ||
82 | case ip of | ||
83 | IPv4 ip4 -> S.put (0x82 :: Word8) >> S.put ip4 | ||
84 | IPv6 ip6 -> S.put (0x8a :: Word8) >> S.put ip6 | ||
85 | S.put tcpport | ||
86 | S.put nid | ||
87 | |||
88 | fromUDPNode :: UDP.NodeInfo -> NodeInfo | ||
89 | fromUDPNode ni = NodeInfo ni 0 | ||