summaryrefslogtreecommitdiff
path: root/src/Network/KRPC/Message.hs
diff options
context:
space:
mode:
authorjoe <joe@jerkface.net>2017-01-17 18:42:09 -0500
committerjoe <joe@jerkface.net>2017-01-17 18:42:09 -0500
commit5d0791e6ed2e500c08e7dadda39a254c8340cef5 (patch)
tree1232e01ea7452473941e488af01b98bc90202554 /src/Network/KRPC/Message.hs
parent5c54f6570a27e1509ddf048a91bd69c05052f2f1 (diff)
Handle reflected IP addresses (see bep 42).
Diffstat (limited to 'src/Network/KRPC/Message.hs')
-rw-r--r--src/Network/KRPC/Message.hs45
1 files changed, 41 insertions, 4 deletions
diff --git a/src/Network/KRPC/Message.hs b/src/Network/KRPC/Message.hs
index ebf5573e..6f4ae620 100644
--- a/src/Network/KRPC/Message.hs
+++ b/src/Network/KRPC/Message.hs
@@ -35,17 +35,22 @@ module Network.KRPC.Message
35 35
36 -- * Response 36 -- * Response
37 , KResponse(..) 37 , KResponse(..)
38 , ReflectedIP(..)
38 39
39 -- * Message 40 -- * Message
40 , KMessage (..) 41 , KMessage (..)
41 ) where 42 ) where
42 43
43import Control.Applicative 44import Control.Applicative
45import Control.Arrow
44import Control.Exception.Lifted as Lifted 46import Control.Exception.Lifted as Lifted
45import Data.BEncode as BE 47import Data.BEncode as BE
46import Data.ByteString as B 48import Data.ByteString as B
47import Data.ByteString.Char8 as BC 49import Data.ByteString.Char8 as BC
50import qualified Data.Serialize as S
51import Data.Word
48import Data.Typeable 52import Data.Typeable
53import Network.Socket (SockAddr (..),PortNumber,HostAddress)
49 54
50 55
51-- | This transaction ID is generated by the querying node and is 56-- | This transaction ID is generated by the querying node and is
@@ -188,6 +193,35 @@ instance BEncode KQuery where
188 KQuery <$>! "a" <*>! "q" <*>! "t" 193 KQuery <$>! "a" <*>! "q" <*>! "t"
189 {-# INLINE fromBEncode #-} 194 {-# INLINE fromBEncode #-}
190 195
196newtype ReflectedIP = ReflectedIP SockAddr
197 deriving (Eq, Ord, Show)
198
199instance BEncode ReflectedIP where
200 toBEncode (ReflectedIP addr) = BString (encodeAddr addr)
201 fromBEncode (BString bs) = ReflectedIP <$> decodeAddr bs
202 fromBEncode _ = Left "ReflectedIP should be a bencoded string"
203
204port16 :: Word16 -> PortNumber
205port16 = fromIntegral
206
207decodeAddr :: ByteString -> Either String SockAddr
208decodeAddr bs | B.length bs == 6
209 = ( \(a,p) -> SockAddrInet <$> fmap port16 p <*> a )
210 $ (S.runGet S.getWord32host *** S.decode )
211 $ B.splitAt 4 bs
212decodeAddr bs | B.length bs == 18
213 = ( \(a,p) -> flip SockAddrInet6 0 <$> fmap port16 p <*> a <*> pure 0 )
214 $ (S.decode *** S.decode )
215 $ B.splitAt 16 bs
216decodeAddr _ = Left "incorrectly sized address and port"
217
218encodeAddr :: SockAddr -> ByteString
219encodeAddr (SockAddrInet port addr)
220 = S.runPut (S.putWord32host addr >> S.put (fromIntegral port :: Word16))
221encodeAddr (SockAddrInet6 port _ addr _)
222 = S.runPut (S.put addr >> S.put (fromIntegral port :: Word16))
223encodeAddr _ = B.empty
224
191{----------------------------------------------------------------------- 225{-----------------------------------------------------------------------
192-- Response messages 226-- Response messages
193-----------------------------------------------------------------------} 227-----------------------------------------------------------------------}
@@ -206,7 +240,8 @@ instance BEncode KQuery where
206data KResponse = KResponse 240data KResponse = KResponse
207 { respVals :: BValue -- ^ 'BDict' containing return values; 241 { respVals :: BValue -- ^ 'BDict' containing return values;
208 , respId :: TransactionId -- ^ match to the corresponding 'queryId'. 242 , respId :: TransactionId -- ^ match to the corresponding 'queryId'.
209 } deriving (Show, Read, Eq, Ord, Typeable) 243 , respIP :: Maybe ReflectedIP
244 } deriving (Show, Eq, Ord, Typeable)
210 245
211-- | Responses, or KRPC message dictionaries with a \"y\" value of 246-- | Responses, or KRPC message dictionaries with a \"y\" value of
212-- \"r\", contain one additional key \"r\". The value of \"r\" is a 247-- \"r\", contain one additional key \"r\". The value of \"r\" is a
@@ -218,7 +253,8 @@ data KResponse = KResponse
218-- 253--
219instance BEncode KResponse where 254instance BEncode KResponse where
220 toBEncode KResponse {..} = toDict $ 255 toBEncode KResponse {..} = toDict $
221 "r" .=! respVals 256 "ip" .=? respIP
257 .: "r" .=! respVals
222 .: "t" .=! respId 258 .: "t" .=! respId
223 .: "y" .=! ("r" :: ByteString) 259 .: "y" .=! ("r" :: ByteString)
224 .: endDict 260 .: endDict
@@ -226,7 +262,8 @@ instance BEncode KResponse where
226 262
227 fromBEncode = fromDict $ do 263 fromBEncode = fromDict $ do
228 lookAhead $ match "y" (BString "r") 264 lookAhead $ match "y" (BString "r")
229 KResponse <$>! "r" <*>! "t" 265 addr <- optional (field (req "ip"))
266 (\r t -> KResponse r t addr) <$>! "r" <*>! "t"
230 {-# INLINE fromBEncode #-} 267 {-# INLINE fromBEncode #-}
231 268
232{----------------------------------------------------------------------- 269{-----------------------------------------------------------------------
@@ -249,4 +286,4 @@ instance BEncode KMessage where
249 Q <$> fromBEncode b 286 Q <$> fromBEncode b
250 <|> R <$> fromBEncode b 287 <|> R <$> fromBEncode b
251 <|> E <$> fromBEncode b 288 <|> E <$> fromBEncode b
252 <|> decodingError "KMessage: unknown message or message tag" \ No newline at end of file 289 <|> decodingError "KMessage: unknown message or message tag"