\begin{code}
{-# LANGUAGE DeriveDataTypeable         #-}
{-# LANGUAGE DeriveGeneric              #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE StrictData                 #-}
{-# LANGUAGE Trustworthy                #-}
module Network.Tox.DHT.RpcPacket where

import           Control.Applicative       ((<$>), (<*>))
import           Data.Binary               (Binary)
import           Data.MessagePack          (MessagePack)
import           Data.Typeable             (Typeable)
import           Data.Word                 (Word64)
import           GHC.Generics              (Generic)
import           Test.QuickCheck.Arbitrary (Arbitrary, arbitrary)

{-------------------------------------------------------------------------------
 -
 - :: Implementation.
 -
 ------------------------------------------------------------------------------}

\end{code}

A DHT RPC Service consists of a Request packet and a Response packet.  A DHT
RPC Packet contains a payload and a Request ID.  This ID is a 64 bit unsigned
integer that helps identify the response for a given request.

\begin{code}

newtype RequestId = RequestId Word64
  deriving (RequestId -> RequestId -> Bool
(RequestId -> RequestId -> Bool)
-> (RequestId -> RequestId -> Bool) -> Eq RequestId
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: RequestId -> RequestId -> Bool
$c/= :: RequestId -> RequestId -> Bool
== :: RequestId -> RequestId -> Bool
$c== :: RequestId -> RequestId -> Bool
Eq, ReadPrec [RequestId]
ReadPrec RequestId
Int -> ReadS RequestId
ReadS [RequestId]
(Int -> ReadS RequestId)
-> ReadS [RequestId]
-> ReadPrec RequestId
-> ReadPrec [RequestId]
-> Read RequestId
forall a.
(Int -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
readListPrec :: ReadPrec [RequestId]
$creadListPrec :: ReadPrec [RequestId]
readPrec :: ReadPrec RequestId
$creadPrec :: ReadPrec RequestId
readList :: ReadS [RequestId]
$creadList :: ReadS [RequestId]
readsPrec :: Int -> ReadS RequestId
$creadsPrec :: Int -> ReadS RequestId
Read, Int -> RequestId -> ShowS
[RequestId] -> ShowS
RequestId -> String
(Int -> RequestId -> ShowS)
-> (RequestId -> String)
-> ([RequestId] -> ShowS)
-> Show RequestId
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [RequestId] -> ShowS
$cshowList :: [RequestId] -> ShowS
show :: RequestId -> String
$cshow :: RequestId -> String
showsPrec :: Int -> RequestId -> ShowS
$cshowsPrec :: Int -> RequestId -> ShowS
Show, Get RequestId
[RequestId] -> Put
RequestId -> Put
(RequestId -> Put)
-> Get RequestId -> ([RequestId] -> Put) -> Binary RequestId
forall t. (t -> Put) -> Get t -> ([t] -> Put) -> Binary t
putList :: [RequestId] -> Put
$cputList :: [RequestId] -> Put
get :: Get RequestId
$cget :: Get RequestId
put :: RequestId -> Put
$cput :: RequestId -> Put
Binary, Gen RequestId
Gen RequestId -> (RequestId -> [RequestId]) -> Arbitrary RequestId
RequestId -> [RequestId]
forall a. Gen a -> (a -> [a]) -> Arbitrary a
shrink :: RequestId -> [RequestId]
$cshrink :: RequestId -> [RequestId]
arbitrary :: Gen RequestId
$carbitrary :: Gen RequestId
Arbitrary, (forall x. RequestId -> Rep RequestId x)
-> (forall x. Rep RequestId x -> RequestId) -> Generic RequestId
forall x. Rep RequestId x -> RequestId
forall x. RequestId -> Rep RequestId x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep RequestId x -> RequestId
$cfrom :: forall x. RequestId -> Rep RequestId x
Generic)

instance MessagePack RequestId

\end{code}

\input{src/Network/Tox/DHT/PendingReplies.lhs}

DHT RPC Packets are encrypted and transported within DHT Packets.

\begin{tabular}{l|l|l}
  Length             & Type               & \href{#dht-packet}{Contents} \\
  \hline
  \texttt{[0,]}      & Bytes              & Payload \\
  \texttt{8}         & \texttt{uint64\_t}  & Request ID \\
\end{tabular}

The minimum payload size is 0, but in reality the smallest sensible payload
size is 1.  Since the same symmetric key is used in both communication
directions, an encrypted Request would be a valid encrypted Response if they
contained the same plaintext.

\begin{code}

data RpcPacket payload = RpcPacket
  { RpcPacket payload -> payload
rpcPayload :: payload
  , RpcPacket payload -> RequestId
requestId  :: RequestId
  }
  deriving (RpcPacket payload -> RpcPacket payload -> Bool
(RpcPacket payload -> RpcPacket payload -> Bool)
-> (RpcPacket payload -> RpcPacket payload -> Bool)
-> Eq (RpcPacket payload)
forall payload.
Eq payload =>
RpcPacket payload -> RpcPacket payload -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: RpcPacket payload -> RpcPacket payload -> Bool
$c/= :: forall payload.
Eq payload =>
RpcPacket payload -> RpcPacket payload -> Bool
== :: RpcPacket payload -> RpcPacket payload -> Bool
$c== :: forall payload.
Eq payload =>
RpcPacket payload -> RpcPacket payload -> Bool
Eq, ReadPrec [RpcPacket payload]
ReadPrec (RpcPacket payload)
Int -> ReadS (RpcPacket payload)
ReadS [RpcPacket payload]
(Int -> ReadS (RpcPacket payload))
-> ReadS [RpcPacket payload]
-> ReadPrec (RpcPacket payload)
-> ReadPrec [RpcPacket payload]
-> Read (RpcPacket payload)
forall payload. Read payload => ReadPrec [RpcPacket payload]
forall payload. Read payload => ReadPrec (RpcPacket payload)
forall payload. Read payload => Int -> ReadS (RpcPacket payload)
forall payload. Read payload => ReadS [RpcPacket payload]
forall a.
(Int -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
readListPrec :: ReadPrec [RpcPacket payload]
$creadListPrec :: forall payload. Read payload => ReadPrec [RpcPacket payload]
readPrec :: ReadPrec (RpcPacket payload)
$creadPrec :: forall payload. Read payload => ReadPrec (RpcPacket payload)
readList :: ReadS [RpcPacket payload]
$creadList :: forall payload. Read payload => ReadS [RpcPacket payload]
readsPrec :: Int -> ReadS (RpcPacket payload)
$creadsPrec :: forall payload. Read payload => Int -> ReadS (RpcPacket payload)
Read, Int -> RpcPacket payload -> ShowS
[RpcPacket payload] -> ShowS
RpcPacket payload -> String
(Int -> RpcPacket payload -> ShowS)
-> (RpcPacket payload -> String)
-> ([RpcPacket payload] -> ShowS)
-> Show (RpcPacket payload)
forall payload. Show payload => Int -> RpcPacket payload -> ShowS
forall payload. Show payload => [RpcPacket payload] -> ShowS
forall payload. Show payload => RpcPacket payload -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [RpcPacket payload] -> ShowS
$cshowList :: forall payload. Show payload => [RpcPacket payload] -> ShowS
show :: RpcPacket payload -> String
$cshow :: forall payload. Show payload => RpcPacket payload -> String
showsPrec :: Int -> RpcPacket payload -> ShowS
$cshowsPrec :: forall payload. Show payload => Int -> RpcPacket payload -> ShowS
Show, (forall x. RpcPacket payload -> Rep (RpcPacket payload) x)
-> (forall x. Rep (RpcPacket payload) x -> RpcPacket payload)
-> Generic (RpcPacket payload)
forall x. Rep (RpcPacket payload) x -> RpcPacket payload
forall x. RpcPacket payload -> Rep (RpcPacket payload) x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
forall payload x. Rep (RpcPacket payload) x -> RpcPacket payload
forall payload x. RpcPacket payload -> Rep (RpcPacket payload) x
$cto :: forall payload x. Rep (RpcPacket payload) x -> RpcPacket payload
$cfrom :: forall payload x. RpcPacket payload -> Rep (RpcPacket payload) x
Generic, Typeable)

instance Binary payload => Binary (RpcPacket payload)
instance MessagePack payload => MessagePack (RpcPacket payload)


{-------------------------------------------------------------------------------
 -
 - :: Tests.
 -
 ------------------------------------------------------------------------------}


instance Arbitrary payload => Arbitrary (RpcPacket payload) where
  arbitrary :: Gen (RpcPacket payload)
arbitrary =
    payload -> RequestId -> RpcPacket payload
forall payload. payload -> RequestId -> RpcPacket payload
RpcPacket (payload -> RequestId -> RpcPacket payload)
-> Gen payload -> Gen (RequestId -> RpcPacket payload)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Gen payload
forall a. Arbitrary a => Gen a
arbitrary Gen (RequestId -> RpcPacket payload)
-> Gen RequestId -> Gen (RpcPacket payload)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Gen RequestId
forall a. Arbitrary a => Gen a
arbitrary
\end{code}

Parts of the protocol using RPC packets must take care to make Request payloads
not be valid Response payloads.  For instance, \href{#ping-service}{Ping
Packets} carry a boolean flag that indicate whether the payload corresponds to
a Request or a Response.

The Request ID provides some resistance against replay attacks.  If there were
no Request ID, it would be easy for an attacker to replay old responses and
thus provide nodes with out-of-date information.  A Request ID should be
randomly generated for each Request which is sent.