\begin{code} {-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# 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 (Eq, Read, Show, Binary, Arbitrary, 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 { rpcPayload :: payload , requestId :: RequestId } deriving (Eq, Read, Show, Generic, Typeable) instance Binary payload => Binary (RpcPacket payload) instance MessagePack payload => MessagePack (RpcPacket payload) {------------------------------------------------------------------------------- - - :: Tests. - ------------------------------------------------------------------------------} instance Arbitrary payload => Arbitrary (RpcPacket payload) where arbitrary = RpcPacket <$> arbitrary <*> 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.