diff options
author | joe <joe@jerkface.net> | 2017-06-08 23:26:30 -0400 |
---|---|---|
committer | joe <joe@jerkface.net> | 2017-06-08 23:26:30 -0400 |
commit | 84798bfef62a001ded1bd628d846612f0b0ade80 (patch) | |
tree | 6a66e1d8fa014bea6f6562650134440a5a515f56 /src/Network | |
parent | cb2bd0bf4b5977ef6ec7ca7ab9ac0189457c2250 (diff) |
Generalized Network.DatagramServer
Diffstat (limited to 'src/Network')
-rw-r--r-- | src/Network/BitTorrent/DHT/Query.hs | 16 | ||||
-rw-r--r-- | src/Network/BitTorrent/DHT/Session.hs | 8 | ||||
-rw-r--r-- | src/Network/DHT/Mainline.hs | 71 | ||||
-rw-r--r-- | src/Network/DatagramServer.hs | 292 | ||||
-rw-r--r-- | src/Network/DatagramServer/Error.hs | 110 | ||||
-rw-r--r-- | src/Network/DatagramServer/Mainline.hs | 236 | ||||
-rw-r--r-- | src/Network/DatagramServer/Tox.hs | 11 | ||||
-rw-r--r-- | src/Network/DatagramServer/Types.hs | 38 |
8 files changed, 414 insertions, 368 deletions
diff --git a/src/Network/BitTorrent/DHT/Query.hs b/src/Network/BitTorrent/DHT/Query.hs index fc6625ae..9adad163 100644 --- a/src/Network/BitTorrent/DHT/Query.hs +++ b/src/Network/BitTorrent/DHT/Query.hs | |||
@@ -82,6 +82,7 @@ import Data.Time | |||
82 | import Data.Time.Clock.POSIX | 82 | import Data.Time.Clock.POSIX |
83 | 83 | ||
84 | import Network.DatagramServer as KRPC hiding (Options, def) | 84 | import Network.DatagramServer as KRPC hiding (Options, def) |
85 | import Network.KRPC.Method as KRPC | ||
85 | import Network.DatagramServer.Mainline (ReflectedIP(..)) | 86 | import Network.DatagramServer.Mainline (ReflectedIP(..)) |
86 | import Network.DatagramServer (QueryFailure(..)) | 87 | import Network.DatagramServer (QueryFailure(..)) |
87 | import Data.Torrent | 88 | import Data.Torrent |
@@ -112,8 +113,8 @@ nodeHandler :: ( Address ip | |||
112 | #else | 113 | #else |
113 | , KPRC.Envelope (Query a) (Response b) ~ ByteString ) | 114 | , KPRC.Envelope (Query a) (Response b) ~ ByteString ) |
114 | #endif | 115 | #endif |
115 | => (NodeAddr ip -> a -> DHT ip b) -> NodeHandler ip | 116 | => QueryMethod KMessageOf -> (NodeAddr ip -> a -> DHT ip b) -> NodeHandler ip |
116 | nodeHandler action = handler $ \ sockAddr qry -> do | 117 | nodeHandler method action = handler method $ \ sockAddr qry -> do |
117 | #ifdef VERSION_bencoding | 118 | #ifdef VERSION_bencoding |
118 | let remoteId = queringNodeId qry | 119 | let remoteId = queringNodeId qry |
119 | read_only = queryIsReadOnly qry | 120 | read_only = queryIsReadOnly qry |
@@ -138,27 +139,27 @@ nodeHandler action = handler $ \ sockAddr qry -> do | |||
138 | -- | Default 'Ping' handler. | 139 | -- | Default 'Ping' handler. |
139 | pingH :: Address ip => NodeHandler ip | 140 | pingH :: Address ip => NodeHandler ip |
140 | #ifdef VERSION_bencoding | 141 | #ifdef VERSION_bencoding |
141 | pingH = nodeHandler $ \ _ Ping -> return Ping | 142 | pingH = nodeHandler "ping" $ \ _ Ping -> return Ping |
142 | #else | 143 | #else |
143 | pingH = nodeHandler $ \ _ p@PingPayload{} -> return p { isPong = True } | 144 | pingH = nodeHandler $ \ _ p@PingPayload{} -> return p { isPong = True } |
144 | #endif | 145 | #endif |
145 | 146 | ||
146 | -- | Default 'FindNode' handler. | 147 | -- | Default 'FindNode' handler. |
147 | findNodeH :: Address ip => NodeHandler ip | 148 | findNodeH :: Address ip => NodeHandler ip |
148 | findNodeH = nodeHandler $ \ _ (FindNode nid) -> do | 149 | findNodeH = nodeHandler "find-nodes" $ \ _ (FindNode nid) -> do |
149 | NodeFound <$> getClosest nid | 150 | NodeFound <$> getClosest nid |
150 | 151 | ||
151 | #ifdef VERSION_bencoding | 152 | #ifdef VERSION_bencoding |
152 | -- | Default 'GetPeers' handler. | 153 | -- | Default 'GetPeers' handler. |
153 | getPeersH :: Ord ip => Address ip => NodeHandler ip | 154 | getPeersH :: Ord ip => Address ip => NodeHandler ip |
154 | getPeersH = nodeHandler $ \ naddr (GetPeers ih) -> do | 155 | getPeersH = nodeHandler "get_peers" $ \ naddr (GetPeers ih) -> do |
155 | ps <- getPeerList ih | 156 | ps <- getPeerList ih |
156 | tok <- grantToken naddr | 157 | tok <- grantToken naddr |
157 | return $ GotPeers ps tok | 158 | return $ GotPeers ps tok |
158 | 159 | ||
159 | -- | Default 'Announce' handler. | 160 | -- | Default 'Announce' handler. |
160 | announceH :: Ord ip => Address ip => NodeHandler ip | 161 | announceH :: Ord ip => Address ip => NodeHandler ip |
161 | announceH = nodeHandler $ \ naddr @ NodeAddr {..} (Announce {..}) -> do | 162 | announceH = nodeHandler "announce_peer" $ \ naddr @ NodeAddr {..} (Announce {..}) -> do |
162 | valid <- checkToken naddr sessionToken | 163 | valid <- checkToken naddr sessionToken |
163 | unless valid $ do | 164 | unless valid $ do |
164 | throwIO $ InvalidParameter "token" | 165 | throwIO $ InvalidParameter "token" |
@@ -396,7 +397,8 @@ queryNode' :: forall a b ip. Address ip => KRPC (Query a) (Response b) | |||
396 | queryNode' addr q = do | 397 | queryNode' addr q = do |
397 | nid <- myNodeIdAccordingTo addr | 398 | nid <- myNodeIdAccordingTo addr |
398 | let read_only = False -- TODO: check for NAT issues. (BEP 43) | 399 | let read_only = False -- TODO: check for NAT issues. (BEP 43) |
399 | (Response remoteId r, witnessed_ip) <- query' (toSockAddr addr) (Query nid read_only q) | 400 | let KRPC.Method name = KRPC.method :: KRPC.Method (Query a) (Response b) |
401 | (Response remoteId r, witnessed_ip) <- query' name (toSockAddr addr) (Query nid read_only q) | ||
400 | -- $(logDebugS) "queryNode" $ "Witnessed address: " <> T.pack (show witnessed_ip) | 402 | -- $(logDebugS) "queryNode" $ "Witnessed address: " <> T.pack (show witnessed_ip) |
401 | -- <> " by " <> T.pack (show (toSockAddr addr)) | 403 | -- <> " by " <> T.pack (show (toSockAddr addr)) |
402 | _ <- insertNode (NodeInfo remoteId addr ()) witnessed_ip | 404 | _ <- insertNode (NodeInfo remoteId addr ()) witnessed_ip |
diff --git a/src/Network/BitTorrent/DHT/Session.hs b/src/Network/BitTorrent/DHT/Session.hs index f874b62e..0c819620 100644 --- a/src/Network/BitTorrent/DHT/Session.hs +++ b/src/Network/BitTorrent/DHT/Session.hs | |||
@@ -85,6 +85,7 @@ import Control.Monad.Logger | |||
85 | import Control.Monad.Reader | 85 | import Control.Monad.Reader |
86 | import Control.Monad.Trans.Control | 86 | import Control.Monad.Trans.Control |
87 | import Control.Monad.Trans.Resource | 87 | import Control.Monad.Trans.Resource |
88 | import Data.Typeable | ||
88 | import Data.ByteString | 89 | import Data.ByteString |
89 | import Data.Conduit.Lazy | 90 | import Data.Conduit.Lazy |
90 | import Data.Default | 91 | import Data.Default |
@@ -266,10 +267,11 @@ data Node ip = Node | |||
266 | #endif | 267 | #endif |
267 | 268 | ||
268 | , resources :: !InternalState | 269 | , resources :: !InternalState |
269 | , manager :: !(Manager (DHT ip )) -- ^ RPC manager; | ||
270 | #ifdef VERSION_bencoding | 270 | #ifdef VERSION_bencoding |
271 | , manager :: !(Manager (DHT ip) BValue KMessageOf) -- ^ RPC manager; | ||
271 | , routingInfo :: !(TVar (Maybe (R.Info KMessageOf ip ()))) -- ^ search table; | 272 | , routingInfo :: !(TVar (Maybe (R.Info KMessageOf ip ()))) -- ^ search table; |
272 | #else | 273 | #else |
274 | , manager :: !(Manager (DHT ip) ByteString Tox.Message) -- ^ RPC manager; | ||
273 | , routingInfo :: !(TVar (Maybe (R.Info Tox.Message ip Bool))) -- ^ search table; | 275 | , routingInfo :: !(TVar (Maybe (R.Info Tox.Message ip Bool))) -- ^ search table; |
274 | #endif | 276 | #endif |
275 | , contactInfo :: !(TVar (PeerStore ip )) -- ^ published by other nodes; | 277 | , contactInfo :: !(TVar (PeerStore ip )) -- ^ published by other nodes; |
@@ -318,7 +320,7 @@ instance MonadResource (DHT ip) where | |||
318 | s <- asks resources | 320 | s <- asks resources |
319 | liftIO $ runInternalState m s | 321 | liftIO $ runInternalState m s |
320 | 322 | ||
321 | instance MonadKRPC (DHT ip) (DHT ip) where | 323 | instance MonadKRPC (DHT ip) (DHT ip) BValue KMessageOf where |
322 | getManager = asks manager | 324 | getManager = asks manager |
323 | 325 | ||
324 | instance MonadLogger (DHT ip) where | 326 | instance MonadLogger (DHT ip) where |
@@ -364,7 +366,7 @@ newNode hs opts naddr logger mbid = do | |||
364 | <*> newTVarIO S.empty | 366 | <*> newTVarIO S.empty |
365 | <*> (newTVarIO =<< nullSessionTokens) | 367 | <*> (newTVarIO =<< nullSessionTokens) |
366 | <*> pure logger | 368 | <*> pure logger |
367 | runReaderT (unDHT KRPC.listen) node | 369 | runReaderT (unDHT $ KRPC.listen (KRPC.Protocol Proxy Proxy)) node |
368 | return node | 370 | return node |
369 | 371 | ||
370 | -- | Some resources like listener thread may live for | 372 | -- | Some resources like listener thread may live for |
diff --git a/src/Network/DHT/Mainline.hs b/src/Network/DHT/Mainline.hs index 7b3d6d55..2ecb9845 100644 --- a/src/Network/DHT/Mainline.hs +++ b/src/Network/DHT/Mainline.hs | |||
@@ -24,46 +24,12 @@ import Data.LargeWord | |||
24 | import Data.Serialize as S | 24 | import Data.Serialize as S |
25 | import Data.String | 25 | import Data.String |
26 | import Data.Typeable | 26 | import Data.Typeable |
27 | import Network.DatagramServer.Mainline (NodeId(..)) | ||
27 | import Network.DatagramServer.Mainline as KRPC | 28 | import Network.DatagramServer.Mainline as KRPC |
28 | import Network.DatagramServer.Types as RPC | 29 | import Network.DatagramServer.Types as RPC |
29 | import Text.PrettyPrint as PP hiding ((<>)) | 30 | import Text.PrettyPrint as PP hiding ((<>)) |
30 | import Text.PrettyPrint.HughesPJClass hiding (($$), (<>)) | 31 | import Text.PrettyPrint.HughesPJClass hiding (($$), (<>)) |
31 | 32 | ||
32 | nodeIdSize = finiteBitSize (undefined :: NodeId KMessageOf) `div` 8 | ||
33 | |||
34 | instance BEncode (NodeId KMessageOf) where | ||
35 | toBEncode (NodeId w) = toBEncode $ S.encode w | ||
36 | fromBEncode bval = fromBEncode bval >>= S.decode | ||
37 | |||
38 | -- instance BEncode NodeId where TODO | ||
39 | |||
40 | -- TODO: put this somewhere appropriate | ||
41 | instance (Serialize a, Serialize b) => Serialize (LargeKey a b) where | ||
42 | put (LargeKey lo hi) = put hi >> put lo | ||
43 | get = flip LargeKey <$> get <*> get | ||
44 | |||
45 | instance Serialize (NodeId KMessageOf) where | ||
46 | get = NodeId <$> get | ||
47 | {-# INLINE get #-} | ||
48 | put (NodeId bs) = put bs | ||
49 | {-# INLINE put #-} | ||
50 | |||
51 | -- | ASCII encoded. | ||
52 | instance IsString (NodeId KMessageOf) where | ||
53 | fromString str | ||
54 | | length str == nodeIdSize = NodeId (either error id $ S.decode (fromString str :: ByteString)) | ||
55 | | length str == 2 * nodeIdSize = NodeId (either error id $ S.decode (fst $ Base16.decode $ fromString str)) | ||
56 | | otherwise = error "fromString: invalid NodeId length" | ||
57 | {-# INLINE fromString #-} | ||
58 | |||
59 | -- | Meaningless node id, for testing purposes only. | ||
60 | instance Default (NodeId KMessageOf) where | ||
61 | def = NodeId 0 | ||
62 | |||
63 | -- | base16 encoded. | ||
64 | instance Pretty (NodeId KMessageOf) where | ||
65 | pPrint (NodeId nid) = PP.text $ Char8.unpack $ Base16.encode $ S.encode nid | ||
66 | |||
67 | -- | KRPC 'compact list' compatible encoding: contact information for | 33 | -- | KRPC 'compact list' compatible encoding: contact information for |
68 | -- nodes is encoded as a 26-byte string. Also known as "Compact node | 34 | -- nodes is encoded as a 26-byte string. Also known as "Compact node |
69 | -- info" the 20-byte Node ID in network byte order has the compact | 35 | -- info" the 20-byte Node ID in network byte order has the compact |
@@ -115,38 +81,3 @@ bep42 addr (NodeId r) | |||
115 | 81 | ||
116 | 82 | ||
117 | 83 | ||
118 | instance Envelope KMessageOf where | ||
119 | type TransactionID KMessageOf = KRPC.TransactionId | ||
120 | |||
121 | -- | Each node has a globally unique identifier known as the \"node | ||
122 | -- ID.\" | ||
123 | -- | ||
124 | -- Normally, /this/ node id should be saved between invocations | ||
125 | -- of the client software. | ||
126 | newtype NodeId KMessageOf = NodeId Word160 | ||
127 | deriving (Show, Eq, Ord, Typeable, Bits, FiniteBits) | ||
128 | |||
129 | envelopePayload (Q q) = queryArgs q | ||
130 | envelopePayload (R r) = respVals r | ||
131 | envelopePayload (E _) = error "TODO: messagePayload for KError" | ||
132 | |||
133 | envelopeTransaction (Q q) = queryId q | ||
134 | envelopeTransaction (R r) = respId r | ||
135 | envelopeTransaction (E e) = errorId e | ||
136 | |||
137 | envelopeClass (Q _) = Query | ||
138 | envelopeClass (R _) = Response | ||
139 | envelopeClass (E _) = Error | ||
140 | |||
141 | buildReply self addr qry response = | ||
142 | (R (KResponse response (envelopeTransaction qry) (Just $ ReflectedIP addr))) | ||
143 | |||
144 | instance WireFormat BValue KMessageOf where | ||
145 | type SerializableTo BValue = BEncode | ||
146 | type CipherContext BValue KMessageOf = () | ||
147 | |||
148 | decodeHeaders _ bs = BE.decode bs >>= BE.fromBEncode | ||
149 | decodePayload kmsg = mapM BE.fromBEncode kmsg | ||
150 | |||
151 | encodeHeaders _ kmsg = L.toStrict $ BE.encode kmsg | ||
152 | encodePayload msg = fmap BE.toBEncode msg | ||
diff --git a/src/Network/DatagramServer.hs b/src/Network/DatagramServer.hs index 21300108..e1bf91c5 100644 --- a/src/Network/DatagramServer.hs +++ b/src/Network/DatagramServer.hs | |||
@@ -60,6 +60,7 @@ | |||
60 | {-# LANGUAGE FunctionalDependencies #-} | 60 | {-# LANGUAGE FunctionalDependencies #-} |
61 | {-# LANGUAGE DeriveDataTypeable #-} | 61 | {-# LANGUAGE DeriveDataTypeable #-} |
62 | {-# LANGUAGE TemplateHaskell #-} | 62 | {-# LANGUAGE TemplateHaskell #-} |
63 | {-# LANGUAGE KindSignatures #-} | ||
63 | module Network.DatagramServer | 64 | module Network.DatagramServer |
64 | ( -- * Methods | 65 | ( -- * Methods |
65 | Method | 66 | Method |
@@ -88,6 +89,7 @@ module Network.DatagramServer | |||
88 | , withManager | 89 | , withManager |
89 | , isActive | 90 | , isActive |
90 | , listen | 91 | , listen |
92 | , Protocol(..) | ||
91 | 93 | ||
92 | -- * Re-exports | 94 | -- * Re-exports |
93 | , ErrorCode (..) | 95 | , ErrorCode (..) |
@@ -96,7 +98,6 @@ module Network.DatagramServer | |||
96 | 98 | ||
97 | import Data.Default.Class | 99 | import Data.Default.Class |
98 | import Network.DatagramServer.Mainline | 100 | import Network.DatagramServer.Mainline |
99 | import Network.KRPC.Method | ||
100 | import Network.Socket (SockAddr (..)) | 101 | import Network.Socket (SockAddr (..)) |
101 | 102 | ||
102 | import Control.Applicative | 103 | import Control.Applicative |
@@ -192,42 +193,38 @@ validateOptions Options {..} | |||
192 | -- Options | 193 | -- Options |
193 | -----------------------------------------------------------------------} | 194 | -----------------------------------------------------------------------} |
194 | 195 | ||
195 | type KResult = Either KError KMessage -- Response | 196 | type KResult msg raw = Either (KError (TransactionID msg)) (msg raw)-- Response |
196 | 197 | ||
197 | type TransactionCounter = IORef Int | 198 | type TransactionCounter = IORef Int |
198 | type CallId = (TransactionId, SockAddr) | 199 | type CallId msg = (TransactionID msg, SockAddr) |
199 | type CallRes = MVar (KQueryArgs, KResult) -- (raw response, decoded response) | 200 | type CallRes msg raw = MVar (raw, KResult msg raw) -- (raw response, decoded response) |
200 | type PendingCalls = IORef (Map CallId CallRes) | 201 | type PendingCalls msg raw = IORef (Map (CallId msg) (CallRes msg raw)) |
201 | 202 | ||
202 | type HandlerBody h msg v = SockAddr -> msg v -> h (Either String (msg v)) | 203 | type HandlerBody h msg v = SockAddr -> msg v -> h (Either String (msg v)) |
203 | 204 | ||
204 | -- | Handler is a function which will be invoked then some /remote/ | 205 | -- | Handler is a function which will be invoked then some /remote/ |
205 | -- node querying /this/ node. | 206 | -- node querying /this/ node. |
206 | type Handler h msg v = (MethodName, HandlerBody h msg v) | 207 | type Handler h msg v = (QueryMethod msg, HandlerBody h msg v) |
207 | 208 | ||
208 | -- | Keep track pending queries made by /this/ node and handle queries | 209 | -- | Keep track pending queries made by /this/ node and handle queries |
209 | -- made by /remote/ nodes. | 210 | -- made by /remote/ nodes. |
210 | data Manager h = Manager | 211 | data Manager h raw msg = Manager |
211 | { sock :: !Socket | 212 | { sock :: !Socket |
212 | , options :: !Options | 213 | , options :: !Options |
213 | , listenerThread :: !(MVar ThreadId) | 214 | , listenerThread :: !(MVar ThreadId) |
214 | , transactionCounter :: {-# UNPACK #-} !TransactionCounter | 215 | , transactionCounter :: {-# UNPACK #-} !TransactionCounter |
215 | , pendingCalls :: {-# UNPACK #-} !PendingCalls | 216 | , pendingCalls :: {-# UNPACK #-} !(PendingCalls msg raw) |
216 | #ifdef VERSION_bencoding | 217 | , handlers :: [Handler h msg raw] |
217 | , handlers :: [Handler h KMessageOf BValue] | ||
218 | #else | ||
219 | , handlers :: [Handler h KMessageOf BC.ByteString] | ||
220 | #endif | ||
221 | } | 218 | } |
222 | 219 | ||
223 | -- | A monad which can perform or handle queries. | 220 | -- | A monad which can perform or handle queries. |
224 | class (MonadBaseControl IO m, MonadLogger m, MonadIO m) | 221 | class (MonadBaseControl IO m, MonadLogger m, MonadIO m) |
225 | => MonadKRPC h m | m -> h where | 222 | => MonadKRPC h m raw msg | m -> h, m -> raw, m -> msg where |
226 | 223 | ||
227 | -- | Ask for manager. | 224 | -- | Ask for manager. |
228 | getManager :: m (Manager h) | 225 | getManager :: m (Manager h raw msg) |
229 | 226 | ||
230 | default getManager :: MonadReader (Manager h) m => m (Manager h) | 227 | default getManager :: MonadReader (Manager h raw msg) m => m (Manager h raw msg) |
231 | getManager = ask | 228 | getManager = ask |
232 | 229 | ||
233 | -- | Can be used to add logging for instance. | 230 | -- | Can be used to add logging for instance. |
@@ -237,7 +234,7 @@ class (MonadBaseControl IO m, MonadLogger m, MonadIO m) | |||
237 | liftHandler = id | 234 | liftHandler = id |
238 | 235 | ||
239 | instance (MonadBaseControl IO h, MonadLogger h, MonadIO h) | 236 | instance (MonadBaseControl IO h, MonadLogger h, MonadIO h) |
240 | => MonadKRPC h (ReaderT (Manager h) h) where | 237 | => MonadKRPC h (ReaderT (Manager h raw msg) h) raw msg where |
241 | 238 | ||
242 | liftHandler = lift | 239 | liftHandler = lift |
243 | 240 | ||
@@ -251,12 +248,8 @@ sockAddrFamily (SockAddrCan _ ) = AF_CAN | |||
251 | -- run 'listen'. | 248 | -- run 'listen'. |
252 | newManager :: Options -- ^ various protocol options; | 249 | newManager :: Options -- ^ various protocol options; |
253 | -> SockAddr -- ^ address to listen on; | 250 | -> SockAddr -- ^ address to listen on; |
254 | #ifdef VERSION_bencoding | 251 | -> [Handler h msg raw] -- ^ handlers to run on incoming queries. |
255 | -> [Handler h KMessageOf BValue] -- ^ handlers to run on incoming queries. | 252 | -> IO (Manager h raw msg) -- ^ new rpc manager. |
256 | #else | ||
257 | -> [Handler h KMessageOf BC.ByteString] -- ^ handlers to run on incoming queries. | ||
258 | #endif | ||
259 | -> IO (Manager h) -- ^ new rpc manager. | ||
260 | newManager opts @ Options {..} servAddr handlers = do | 253 | newManager opts @ Options {..} servAddr handlers = do |
261 | validateOptions opts | 254 | validateOptions opts |
262 | sock <- bindServ | 255 | sock <- bindServ |
@@ -274,7 +267,7 @@ newManager opts @ Options {..} servAddr handlers = do | |||
274 | return sock | 267 | return sock |
275 | 268 | ||
276 | -- | Unblock all pending calls and close socket. | 269 | -- | Unblock all pending calls and close socket. |
277 | closeManager :: Manager m -> IO () | 270 | closeManager :: Manager m raw msg -> IO () |
278 | closeManager Manager {..} = do | 271 | closeManager Manager {..} = do |
279 | maybe (return ()) killThread =<< tryTakeMVar listenerThread | 272 | maybe (return ()) killThread =<< tryTakeMVar listenerThread |
280 | -- TODO unblock calls | 273 | -- TODO unblock calls |
@@ -282,18 +275,14 @@ closeManager Manager {..} = do | |||
282 | 275 | ||
283 | -- | Check if the manager is still active. Manager becomes active | 276 | -- | Check if the manager is still active. Manager becomes active |
284 | -- until 'closeManager' called. | 277 | -- until 'closeManager' called. |
285 | isActive :: Manager m -> IO Bool | 278 | isActive :: Manager m raw msg -> IO Bool |
286 | isActive Manager {..} = liftIO $ isBound sock | 279 | isActive Manager {..} = liftIO $ isBound sock |
287 | {-# INLINE isActive #-} | 280 | {-# INLINE isActive #-} |
288 | 281 | ||
289 | -- | Normally you should use Control.Monad.Trans.Resource.allocate | 282 | -- | Normally you should use Control.Monad.Trans.Resource.allocate |
290 | -- function. | 283 | -- function. |
291 | #ifdef VERSION_bencoding | 284 | withManager :: Options -> SockAddr -> [Handler h msg raw] |
292 | withManager :: Options -> SockAddr -> [Handler h KMessageOf BValue] | 285 | -> (Manager h raw msg -> IO a) -> IO a |
293 | #else | ||
294 | withManager :: Options -> SockAddr -> [Handler h KMessageOf BC.ByteString] | ||
295 | #endif | ||
296 | -> (Manager h -> IO a) -> IO a | ||
297 | withManager opts addr hs = bracket (newManager opts addr hs) closeManager | 286 | withManager opts addr hs = bracket (newManager opts addr hs) closeManager |
298 | 287 | ||
299 | {----------------------------------------------------------------------- | 288 | {----------------------------------------------------------------------- |
@@ -301,15 +290,12 @@ withManager opts addr hs = bracket (newManager opts addr hs) closeManager | |||
301 | -----------------------------------------------------------------------} | 290 | -----------------------------------------------------------------------} |
302 | 291 | ||
303 | -- TODO prettify log messages | 292 | -- TODO prettify log messages |
304 | querySignature :: MethodName -> TransactionId -> SockAddr -> Text | 293 | querySignature :: ( Show ( QueryMethod msg ) |
294 | , Serialize ( TransactionID msg ) ) | ||
295 | => QueryMethod msg -> TransactionID msg -> SockAddr -> Text | ||
305 | querySignature name transaction addr = T.concat | 296 | querySignature name transaction addr = T.concat |
306 | #ifdef VERSION_bencoding | ||
307 | [ "&", T.decodeUtf8 name | ||
308 | , " #", T.decodeUtf8 (Base16.encode transaction) -- T.decodeUtf8 transaction | ||
309 | #else | ||
310 | [ "&", T.pack (show name) | 297 | [ "&", T.pack (show name) |
311 | , " #", T.decodeUtf8 (Base16.encode $ S.encode transaction) | 298 | , " #", T.decodeUtf8 (Base16.encode $ S.encode transaction) |
312 | #endif | ||
313 | , " @", T.pack (show addr) | 299 | , " @", T.pack (show addr) |
314 | ] | 300 | ] |
315 | 301 | ||
@@ -332,23 +318,19 @@ sendMessage :: MonadIO m => Socket -> SockAddr -> BC.ByteString -> m () | |||
332 | sendMessage sock addr a = do | 318 | sendMessage sock addr a = do |
333 | liftIO $ sendManyTo sock [a] addr | 319 | liftIO $ sendManyTo sock [a] addr |
334 | 320 | ||
335 | genTransactionId :: TransactionCounter -> IO TransactionId | 321 | genTransactionId :: Envelope msg => TransactionCounter -> IO (TransactionID msg) |
336 | genTransactionId ref = do | 322 | genTransactionId ref = do |
337 | cur <- atomicModifyIORef' ref $ \ cur -> (succ cur, cur) | 323 | cur <- atomicModifyIORef' ref $ \ cur -> (succ cur, cur) |
338 | #ifdef VERSION_bencoding | 324 | uniqueTransactionId cur |
339 | return $ BC.pack (show cur) | ||
340 | #else | ||
341 | return $ either (error "failed to create TransactionId") id $ S.decode $ BC.pack (L.take 24 $ show cur ++ L.repeat ' ') | ||
342 | #endif | ||
343 | 325 | ||
344 | -- | How many times 'query' call have been performed. | 326 | -- | How many times 'query' call have been performed. |
345 | getQueryCount :: MonadKRPC h m => m Int | 327 | getQueryCount :: MonadKRPC h m raw msg => m Int |
346 | getQueryCount = do | 328 | getQueryCount = do |
347 | Manager {..} <- getManager | 329 | Manager {..} <- getManager |
348 | curTrans <- liftIO $ readIORef transactionCounter | 330 | curTrans <- liftIO $ readIORef transactionCounter |
349 | return $ curTrans - optSeedTransaction options | 331 | return $ curTrans - optSeedTransaction options |
350 | 332 | ||
351 | registerQuery :: CallId -> PendingCalls -> IO CallRes | 333 | registerQuery :: Ord (TransactionID msg) => CallId msg -> PendingCalls msg raw -> IO (CallRes msg raw) |
352 | registerQuery cid ref = do | 334 | registerQuery cid ref = do |
353 | ares <- newEmptyMVar | 335 | ares <- newEmptyMVar |
354 | atomicModifyIORef' ref $ \ m -> (M.insert cid ares m, ()) | 336 | atomicModifyIORef' ref $ \ m -> (M.insert cid ares m, ()) |
@@ -356,7 +338,7 @@ registerQuery cid ref = do | |||
356 | 338 | ||
357 | -- simultaneous M.lookup and M.delete guarantees that we never get two | 339 | -- simultaneous M.lookup and M.delete guarantees that we never get two |
358 | -- or more responses to the same query | 340 | -- or more responses to the same query |
359 | unregisterQuery :: CallId -> PendingCalls -> IO (Maybe CallRes) | 341 | unregisterQuery :: Ord (TransactionID msg) => CallId msg -> PendingCalls msg raw -> IO (Maybe (CallRes msg raw)) |
360 | unregisterQuery cid ref = do | 342 | unregisterQuery cid ref = do |
361 | atomicModifyIORef' ref $ swap . | 343 | atomicModifyIORef' ref $ swap . |
362 | M.updateLookupWithKey (const (const Nothing)) cid | 344 | M.updateLookupWithKey (const (const Nothing)) cid |
@@ -374,35 +356,37 @@ sendQuery sock addr q = handle sockError $ sendMessage sock addr q | |||
374 | -- This function should throw 'QueryFailure' exception if quered node | 356 | -- This function should throw 'QueryFailure' exception if quered node |
375 | -- respond with @error@ message or the query timeout expires. | 357 | -- respond with @error@ message or the query timeout expires. |
376 | -- | 358 | -- |
377 | query :: forall h m a b. (MonadKRPC h m, KRPC a b) => SockAddr -> a -> m b | 359 | query :: forall h m a b raw msg. (SerializableTo raw b, Show (QueryMethod msg), Ord (TransactionID msg), Serialize (TransactionID msg), SerializableTo raw a, MonadKRPC h m raw msg, WireFormat raw msg, KRPC a b) => QueryMethod msg -> SockAddr -> a -> m b |
378 | query addr params = queryK addr params (\_ x _ -> x) | 360 | query meth addr params = queryK meth addr params (\_ x _ -> x) |
379 | 361 | ||
380 | -- | Like 'query' but possibly returns your externally routable IP address. | 362 | -- | Like 'query' but possibly returns your externally routable IP address. |
381 | query' :: forall h m a b. (MonadKRPC h m, KRPC a b) => SockAddr -> a -> m (b, Maybe ReflectedIP) | 363 | query' :: forall h m a b raw msg. (SerializableTo raw b, Show (QueryMethod msg), Ord (TransactionID msg), Serialize (TransactionID msg), SerializableTo raw a, MonadKRPC h m raw msg, WireFormat raw msg, KRPC a b) => QueryMethod msg -> SockAddr -> a -> m (b, Maybe ReflectedIP) |
382 | query' addr params = queryK addr params (const (,)) | 364 | query' meth addr params = queryK meth addr params (const (,)) |
383 | 365 | ||
384 | -- | Enqueue a query, but give us the complete BEncoded content sent by the | 366 | -- | Enqueue a query, but give us the complete BEncoded content sent by the |
385 | -- remote Node. This is useful for handling extensions that this library does | 367 | -- remote Node. This is useful for handling extensions that this library does |
386 | -- not otherwise support. | 368 | -- not otherwise support. |
387 | queryRaw :: forall h m a b. (MonadKRPC h m, KRPC a b) => SockAddr -> a -> m (b, KQueryArgs) | 369 | queryRaw :: forall h m a b raw msg. (SerializableTo raw b, Show (QueryMethod msg), Ord (TransactionID msg), Serialize (TransactionID msg), SerializableTo raw a, MonadKRPC h m raw msg, WireFormat raw msg, KRPC a b) => QueryMethod msg -> SockAddr -> a -> m (b, raw) |
388 | queryRaw addr params = queryK addr params (\raw x _ -> (x,raw)) | 370 | queryRaw meth addr params = queryK meth addr params (\raw x _ -> (x,raw)) |
389 | 371 | ||
390 | queryK :: forall h m a b x. (MonadKRPC h m, KRPC a b) => | 372 | queryK :: forall h m a b x raw msg. (SerializableTo raw b, Show (QueryMethod msg), Ord (TransactionID msg), Serialize (TransactionID msg), SerializableTo raw a, MonadKRPC h m raw msg, WireFormat raw msg, KRPC a b) => |
391 | SockAddr -> a -> (KQueryArgs -> b -> Maybe ReflectedIP -> x) -> m x | 373 | QueryMethod msg -> SockAddr -> a -> (raw -> b -> Maybe ReflectedIP -> x) -> m x |
392 | queryK addr params kont = do | 374 | queryK meth addr params kont = do |
393 | Manager {..} <- getManager | 375 | Manager {..} <- getManager |
394 | tid <- liftIO $ genTransactionId transactionCounter | 376 | tid <- liftIO $ genTransactionId transactionCounter |
395 | let queryMethod = method :: Method a b | 377 | -- let queryMethod = method :: Method a b |
396 | let signature = querySignature (methodName queryMethod) tid addr | 378 | let signature = querySignature meth tid addr |
397 | $(logDebugS) "query.sending" signature | 379 | $(logDebugS) "query.sending" signature |
398 | 380 | ||
399 | mres <- liftIO $ do | 381 | mres <- liftIO $ do |
400 | ares <- registerQuery (tid, addr) pendingCalls | 382 | ares <- registerQuery (tid, addr) pendingCalls |
401 | 383 | ||
384 | let cli = error "TODO TOX client node id" | ||
385 | ctx = error "TODO TOX ToxCipherContext or () for Mainline" | ||
386 | q <- buildQuery cli addr meth tid params | ||
387 | let qb = encodePayload (q :: msg a) :: msg raw | ||
388 | qbs = encodeHeaders ctx qb | ||
402 | #ifdef VERSION_bencoding | 389 | #ifdef VERSION_bencoding |
403 | let q = Q (KQuery (toBEncode params) (methodName queryMethod) tid) | ||
404 | qb = encodePayload q :: KMessage | ||
405 | qbs = encodeHeaders () qb :: BC.ByteString | ||
406 | #else | 390 | #else |
407 | let q = Tox.Message (methodName queryMethod) cli tid params | 391 | let q = Tox.Message (methodName queryMethod) cli tid params |
408 | cli = error "TODO TOX client node id" | 392 | cli = error "TODO TOX client node id" |
@@ -416,18 +400,13 @@ queryK addr params kont = do | |||
416 | timeout (optQueryTimeout options * 10 ^ (6 :: Int)) $ do | 400 | timeout (optQueryTimeout options * 10 ^ (6 :: Int)) $ do |
417 | (raw,res) <- readMVar ares -- MVar (KQueryArgs, KResult) | 401 | (raw,res) <- readMVar ares -- MVar (KQueryArgs, KResult) |
418 | case res of | 402 | case res of |
419 | #ifdef VERSION_bencoding | ||
420 | Left (KError c m _) -> throwIO $ QueryFailed c (T.decodeUtf8 m) | 403 | Left (KError c m _) -> throwIO $ QueryFailed c (T.decodeUtf8 m) |
421 | Right (R (KResponse {..})) -> | 404 | Right m -> case decodePayload m of |
422 | case fromBEncode respVals of | 405 | Right r -> case envelopeClass (r :: msg b) of |
423 | Right r -> pure $ kont raw r respIP | 406 | Response reflectedAddr -> pure $ kont raw (envelopePayload r) reflectedAddr |
424 | #else | 407 | Error (KError c m _) -> throwIO $ QueryFailed c (T.decodeUtf8 m) -- XXX neccessary? |
425 | Left _ -> throwIO $ QueryFailed GenericError "TODO: TOX ERROR" | 408 | Query _ -> throwIO $ QueryFailed ProtocolError "BUG!! UNREACHABLE" |
426 | Right (Tox.Message {..}) -> | 409 | Left e -> throwIO $ QueryFailed ProtocolError (T.pack e) |
427 | case S.decode msgPayload of | ||
428 | Right r -> pure $ kont raw r Nothing | ||
429 | #endif | ||
430 | Left e -> throwIO $ QueryFailed ProtocolError (T.pack e) | ||
431 | 410 | ||
432 | case mres of | 411 | case mres of |
433 | Just res -> do | 412 | Just res -> do |
@@ -477,43 +456,33 @@ prettyQF e = T.encodeUtf8 $ "handler fail while performing query: " | |||
477 | -- If the handler make some 'query' normally it /should/ handle | 456 | -- If the handler make some 'query' normally it /should/ handle |
478 | -- corresponding 'QueryFailure's. | 457 | -- corresponding 'QueryFailure's. |
479 | -- | 458 | -- |
480 | handler :: forall h a b msg raw. (KRPC a b, Applicative h, Functor msg, WireFormat raw msg, SerializableTo raw a, SerializableTo raw b) | 459 | handler :: forall h a b msg raw. (Applicative h, Functor msg, WireFormat raw msg, SerializableTo raw a, SerializableTo raw b) |
481 | => (SockAddr -> a -> h b) -> Handler h msg raw | 460 | => QueryMethod msg -> (SockAddr -> a -> h b) -> Handler h msg raw |
482 | handler body = (name, wrapper) | 461 | handler name body = (name, wrapper) |
483 | where | 462 | where |
484 | Method name = method :: Method a b | ||
485 | wrapper :: SockAddr -> msg raw -> h (Either String (msg raw)) | 463 | wrapper :: SockAddr -> msg raw -> h (Either String (msg raw)) |
486 | wrapper addr args = | 464 | wrapper addr args = |
487 | case decodePayload args of | 465 | case decodePayload args of |
488 | Left e -> pure $ Left e | 466 | Left e -> pure $ Left e |
489 | Right a -> Right . encodePayload . buildReply (error "self node-id") addr args <$> body addr (envelopePayload a) | 467 | Right a -> Right . encodePayload . buildReply (error "self node-id") addr args <$> body addr (envelopePayload a) |
490 | 468 | ||
491 | runHandler :: MonadKRPC h m | 469 | runHandler :: ( MonadKRPC h m raw msg |
492 | #ifdef VERSION_bencoding | 470 | , Envelope msg |
493 | => HandlerBody h KMessageOf BValue -> SockAddr -> KQuery -> m KResult | 471 | , Show (QueryMethod msg) |
494 | #else | 472 | , Serialize (TransactionID msg)) |
495 | => HandlerBody h KMessageOf BC.ByteString -> SockAddr -> KQuery -> m KResult | 473 | => QueryMethod msg -> HandlerBody h msg raw -> SockAddr -> msg raw -> m (KResult msg raw) |
496 | #endif | 474 | runHandler meth h addr m = Lifted.catches wrapper failbacks |
497 | runHandler h addr m = Lifted.catches wrapper failbacks | ||
498 | where | 475 | where |
499 | signature = querySignature (queryMethod m) (queryId m) addr | 476 | signature = querySignature meth (envelopeTransaction m) addr |
500 | 477 | ||
501 | wrapper = do | 478 | wrapper = do |
502 | $(logDebugS) "handler.quered" signature | 479 | $(logDebugS) "handler.quered" signature |
503 | #ifdef VERSION_bencoding | ||
504 | result <- liftHandler (h addr (Q m)) | ||
505 | #else | ||
506 | result <- liftHandler (h addr m) | 480 | result <- liftHandler (h addr m) |
507 | #endif | ||
508 | 481 | ||
509 | case result of | 482 | case result of |
510 | Left msg -> do | 483 | Left msg -> do |
511 | $(logDebugS) "handler.bad_query" $ signature <> " !" <> T.pack msg | 484 | $(logDebugS) "handler.bad_query" $ signature <> " !" <> T.pack msg |
512 | #ifdef VERSION_bencoding | 485 | return $ Left $ KError ProtocolError (BC.pack msg) (envelopeTransaction m) |
513 | return $ Left $ KError ProtocolError (BC.pack msg) (queryId m) | ||
514 | #else | ||
515 | return $ Left $ decodeError "TODO TOX ProtocolError" (queryId m) | ||
516 | #endif | ||
517 | 486 | ||
518 | Right a -> do -- KQueryArgs | 487 | Right a -> do -- KQueryArgs |
519 | $(logDebugS) "handler.success" signature | 488 | $(logDebugS) "handler.success" signature |
@@ -522,41 +491,30 @@ runHandler h addr m = Lifted.catches wrapper failbacks | |||
522 | failbacks = | 491 | failbacks = |
523 | [ E.Handler $ \ (e :: HandlerFailure) -> do | 492 | [ E.Handler $ \ (e :: HandlerFailure) -> do |
524 | $(logDebugS) "handler.failed" signature | 493 | $(logDebugS) "handler.failed" signature |
525 | #ifdef VERSION_bencoding | 494 | return $ Left $ KError ProtocolError (prettyHF e) (envelopeTransaction m) |
526 | return $ Left $ KError ProtocolError (prettyHF e) (queryId m) | ||
527 | #else | ||
528 | return $ Left $ decodeError "TODO TOX ProtocolError 2" (queryId m) | ||
529 | #endif | ||
530 | 495 | ||
531 | 496 | ||
532 | -- may happen if handler makes query and fail | 497 | -- may happen if handler makes query and fail |
533 | , E.Handler $ \ (e :: QueryFailure) -> do | 498 | , E.Handler $ \ (e :: QueryFailure) -> do |
534 | #ifdef VERSION_bencoding | 499 | return $ Left $ KError ServerError (prettyQF e) (envelopeTransaction m) |
535 | return $ Left $ KError ServerError (prettyQF e) (queryId m) | ||
536 | #else | ||
537 | return $ Left $ decodeError "TODO TOX ServerError" (queryId m) | ||
538 | #endif | ||
539 | 500 | ||
540 | -- since handler thread exit after sendMessage we can safely | 501 | -- since handler thread exit after sendMessage we can safely |
541 | -- suppress async exception here | 502 | -- suppress async exception here |
542 | , E.Handler $ \ (e :: SomeException) -> do | 503 | , E.Handler $ \ (e :: SomeException) -> do |
543 | #ifdef VERSION_bencoding | 504 | return $ Left $ KError GenericError (BC.pack (show e)) (envelopeTransaction m) |
544 | return $ Left $ KError GenericError (BC.pack (show e)) (queryId m) | ||
545 | #else | ||
546 | return $ Left $ decodeError "TODO TOX GenericError" (queryId m) | ||
547 | #endif | ||
548 | ] | 505 | ] |
549 | 506 | ||
550 | dispatchHandler :: MonadKRPC h m => KQuery -> SockAddr -> m KResult | 507 | dispatchHandler :: ( MonadKRPC h m raw msg |
551 | dispatchHandler q addr = do | 508 | , Eq (QueryMethod msg) |
509 | , Show (QueryMethod msg) | ||
510 | , Serialize (TransactionID msg) | ||
511 | , Envelope msg | ||
512 | ) => QueryMethod msg -> msg raw -> SockAddr -> m (KResult msg raw) | ||
513 | dispatchHandler meth q addr = do | ||
552 | Manager {..} <- getManager | 514 | Manager {..} <- getManager |
553 | case L.lookup (queryMethod q) handlers of | 515 | case L.lookup meth handlers of |
554 | #ifdef VERSION_bencoding | 516 | Nothing -> return $ Left $ KError MethodUnknown ("Unknown method " <> BC.pack (show meth)) (envelopeTransaction q) |
555 | Nothing -> return $ Left $ KError MethodUnknown (queryMethod q) (queryId q) | 517 | Just h -> runHandler meth h addr q |
556 | #else | ||
557 | Nothing -> return $ Left $ decodeError "TODO TOX Error MethodUnknown" (queryId q) | ||
558 | #endif | ||
559 | Just h -> runHandler h addr q | ||
560 | 518 | ||
561 | {----------------------------------------------------------------------- | 519 | {----------------------------------------------------------------------- |
562 | -- Listener | 520 | -- Listener |
@@ -569,71 +527,75 @@ dispatchHandler q addr = do | |||
569 | -- peer B fork too many threads | 527 | -- peer B fork too many threads |
570 | -- ... space leak | 528 | -- ... space leak |
571 | -- | 529 | -- |
572 | handleQuery :: MonadKRPC h m => KQueryArgs -> KQuery -> SockAddr -> m () | 530 | handleQuery :: ( MonadKRPC h m raw msg |
573 | handleQuery raw q addr = void $ fork $ do | 531 | , WireFormat raw msg |
532 | , Eq (QueryMethod msg) | ||
533 | , Show (QueryMethod msg) | ||
534 | , Serialize (TransactionID msg) | ||
535 | ) => QueryMethod msg -> raw -> msg raw -> SockAddr -> m () | ||
536 | handleQuery meth raw q addr = void $ fork $ do | ||
574 | myThreadId >>= liftIO . flip labelThread "KRPC.handleQuery" | 537 | myThreadId >>= liftIO . flip labelThread "KRPC.handleQuery" |
575 | Manager {..} <- getManager | 538 | Manager {..} <- getManager |
576 | res <- dispatchHandler q addr | 539 | res <- dispatchHandler meth q addr |
577 | #ifdef VERSION_bencoding | 540 | #ifdef VERSION_bencoding |
578 | let res' = either E id res | 541 | let res' = either buildError Just res |
579 | resbe = either toBEncode toBEncode res | 542 | ctx = error "TODO TOX ToxCipherContext 2 or () for Mainline" |
580 | $(logOther "q") $ T.unlines | 543 | resbs = fmap (encodeHeaders ctx) res' :: Maybe BS.ByteString |
581 | [ either (const "<unicode-fail>") id $ T.decodeUtf8' (BL.toStrict $ showBEncode raw) | 544 | -- TODO: Generalize this debug print. |
582 | , "==>" | 545 | -- resbe = either toBEncode toBEncode res |
583 | , either (const "<unicode-fail>") id $ T.decodeUtf8' (BL.toStrict $ showBEncode resbe) | 546 | -- $(logOther "q") $ T.unlines |
584 | ] | 547 | -- [ either (const "<unicode-fail>") id $ T.decodeUtf8' (BL.toStrict $ showBEncode raw) |
585 | sendMessage sock addr $ encodeHeaders () res' | 548 | -- , "==>" |
549 | -- , either (const "<unicode-fail>") id $ T.decodeUtf8' (BL.toStrict $ showBEncode resbe) | ||
550 | -- ] | ||
551 | maybe (return ()) (sendMessage sock addr) resbs | ||
586 | #else | 552 | #else |
587 | -- Errors not sent for Tox. | 553 | -- Errors not sent for Tox. |
588 | let ctx = error "TODO TOX ToxCipherContext 2" | 554 | let ctx = error "TODO TOX ToxCipherContext 2" |
589 | either (const $ return ()) (sendMessage sock addr . encodeHeaders ctx) res | 555 | either (const $ return ()) (sendMessage sock addr . encodeHeaders ctx) res |
590 | #endif | 556 | #endif |
591 | 557 | ||
592 | handleResponse :: MonadKRPC h m => KQueryArgs -> KResult -> SockAddr -> m () | 558 | handleResponse :: ( MonadKRPC h m raw msg |
559 | , Ord (TransactionID msg) | ||
560 | , Envelope msg | ||
561 | ) => raw -> KResult msg raw -> SockAddr -> m () | ||
593 | handleResponse raw result addr = do | 562 | handleResponse raw result addr = do |
594 | Manager {..} <- getManager | 563 | Manager {..} <- getManager |
595 | liftIO $ do | 564 | liftIO $ do |
596 | #ifdef VERSION_bencoding | ||
597 | let resultId = either errorId envelopeTransaction result | 565 | let resultId = either errorId envelopeTransaction result |
598 | #else | ||
599 | let resultId = either Tox.msgNonce Tox.msgNonce result | ||
600 | #endif | ||
601 | mcall <- unregisterQuery (resultId, addr) pendingCalls | 566 | mcall <- unregisterQuery (resultId, addr) pendingCalls |
602 | case mcall of | 567 | case mcall of |
603 | Nothing -> return () | 568 | Nothing -> return () |
604 | Just ares -> putMVar ares (raw,result) | 569 | Just ares -> putMVar ares (raw,result) |
605 | 570 | ||
606 | #ifdef VERSION_bencoding | 571 | data Protocol raw (msg :: * -> *) = Protocol { rawProxy :: !(Proxy raw) |
607 | handleMessage :: MonadKRPC h m => KQueryArgs -> KMessage -> SockAddr -> m () | 572 | , msgProxy :: !(Proxy msg) |
608 | handleMessage raw (Q q) = handleQuery raw q | 573 | } |
609 | handleMessage raw (R r) = handleResponse raw (Right (R r)) | 574 | |
610 | handleMessage raw (E e) = handleResponse raw (Left e) | 575 | listener :: forall h m raw msg. |
611 | #else | 576 | ( MonadKRPC h m raw msg |
612 | handleMessage :: MonadKRPC h m => KQueryArgs -> Tox.Message BC.ByteString -> SockAddr -> m () | 577 | , WireFormat raw msg |
613 | handleMessage raw q | Tox.isQuery q = handleQuery raw q | 578 | , Ord (TransactionID msg) |
614 | handleMessage raw r | Tox.isResponse r = handleResponse raw (Right r) | 579 | , Eq (QueryMethod msg) |
615 | handleMessage raw e | Tox.isError e = handleResponse raw (Left e) | 580 | , Show (QueryMethod msg) |
616 | #endif | 581 | , Serialize (TransactionID msg) |
617 | 582 | ) => Protocol raw msg -> m () | |
618 | listener :: MonadKRPC h m => m () | 583 | listener p = do |
619 | listener = do | ||
620 | Manager {..} <- getManager | 584 | Manager {..} <- getManager |
621 | fix $ \again -> do | 585 | fix $ \again -> do |
622 | let ctx = error "TODO TOX ToxCipherContext 3" | 586 | let ctx = error "TODO TOX ToxCipherContext or () for Mainline" |
623 | (bs, addr) <- liftIO $ do | 587 | (bs, addr) <- liftIO $ do |
624 | handle exceptions $ BS.recvFrom sock (optMaxMsgSize options) | 588 | handle exceptions $ BS.recvFrom sock (optMaxMsgSize options) |
625 | #ifdef VERSION_bencoding | 589 | case parsePacket (msgProxy p) bs >>= \r -> (,) r <$> decodeHeaders ctx r of |
626 | case BE.parse bs >>= \r -> (,) r <$> BE.decode bs of | 590 | Left e -> -- XXX: Send parse failure message? |
627 | #else | 591 | -- liftIO $ sendMessage sock addr $ encodeHeaders ctx (unknownMessage e) |
628 | case return bs >>= \r -> (,) r <$> decodeHeaders ctx bs of | 592 | return () -- Without transaction id, error message isn't very useful. |
629 | #endif | 593 | Right (raw,m) -> |
630 | -- TODO ignore unknown messages at all? | 594 | case envelopeClass m of |
631 | #ifdef VERSION_bencoding | 595 | Query meth -> handleQuery meth (raw::raw) m addr |
632 | Left e -> liftIO $ sendMessage sock addr $ encodeHeaders () (E (unknownMessage e) :: KMessage) | 596 | Response _ -> handleResponse raw (Right m) addr |
633 | #else | 597 | Error e -> handleResponse raw (Left e) addr |
634 | Left _ -> return () -- TODO TOX send unknownMessage error | 598 | |
635 | #endif | ||
636 | Right (raw,m) -> handleMessage raw m addr | ||
637 | again | 599 | again |
638 | where | 600 | where |
639 | exceptions :: IOError -> IO (BS.ByteString, SockAddr) | 601 | exceptions :: IOError -> IO (BS.ByteString, SockAddr) |
@@ -644,11 +606,17 @@ listener = do | |||
644 | 606 | ||
645 | -- | Should be run before any 'query', otherwise they will never | 607 | -- | Should be run before any 'query', otherwise they will never |
646 | -- succeed. | 608 | -- succeed. |
647 | listen :: MonadKRPC h m => m () | 609 | listen :: ( MonadKRPC h m raw msg |
648 | listen = do | 610 | , WireFormat raw msg |
611 | , Ord (TransactionID msg) | ||
612 | , Eq (QueryMethod msg) | ||
613 | , Show (QueryMethod msg) | ||
614 | , Serialize (TransactionID msg) | ||
615 | ) => Protocol raw msg -> m () | ||
616 | listen p = do | ||
649 | Manager {..} <- getManager | 617 | Manager {..} <- getManager |
650 | tid <- fork $ do | 618 | tid <- fork $ do |
651 | myThreadId >>= liftIO . flip labelThread "KRPC.listen" | 619 | myThreadId >>= liftIO . flip labelThread "KRPC.listen" |
652 | listener `Lifted.finally` | 620 | listener p `Lifted.finally` |
653 | liftIO (takeMVar listenerThread) | 621 | liftIO (takeMVar listenerThread) |
654 | liftIO $ putMVar listenerThread tid | 622 | liftIO $ putMVar listenerThread tid |
diff --git a/src/Network/DatagramServer/Error.hs b/src/Network/DatagramServer/Error.hs new file mode 100644 index 00000000..2cbb76c3 --- /dev/null +++ b/src/Network/DatagramServer/Error.hs | |||
@@ -0,0 +1,110 @@ | |||
1 | {-# LANGUAGE CPP #-} | ||
2 | {-# LANGUAGE DeriveDataTypeable #-} | ||
3 | module Network.DatagramServer.Error where | ||
4 | |||
5 | import Control.Exception.Lifted as Lifted | ||
6 | #ifdef VERSION_bencoding | ||
7 | import Data.BEncode as BE | ||
8 | #endif | ||
9 | import Data.ByteString (ByteString) | ||
10 | import Data.ByteString.Char8 as Char8 | ||
11 | import Data.Data | ||
12 | import Data.Default | ||
13 | import Data.Typeable | ||
14 | |||
15 | {----------------------------------------------------------------------- | ||
16 | -- Error messages | ||
17 | -----------------------------------------------------------------------} | ||
18 | |||
19 | -- | Types of RPC errors. | ||
20 | data ErrorCode | ||
21 | -- | Some error doesn't fit in any other category. | ||
22 | = GenericError | ||
23 | |||
24 | -- | Occur when server fail to process procedure call. | ||
25 | | ServerError | ||
26 | |||
27 | -- | Malformed packet, invalid arguments or bad token. | ||
28 | | ProtocolError | ||
29 | |||
30 | -- | Occur when client trying to call method server don't know. | ||
31 | | MethodUnknown | ||
32 | deriving (Show, Read, Eq, Ord, Bounded, Typeable, Data) | ||
33 | |||
34 | -- | According to the table: | ||
35 | -- <http://bittorrent.org/beps/bep_0005.html#errors> | ||
36 | instance Enum ErrorCode where | ||
37 | fromEnum GenericError = 201 | ||
38 | fromEnum ServerError = 202 | ||
39 | fromEnum ProtocolError = 203 | ||
40 | fromEnum MethodUnknown = 204 | ||
41 | {-# INLINE fromEnum #-} | ||
42 | |||
43 | toEnum 201 = GenericError | ||
44 | toEnum 202 = ServerError | ||
45 | toEnum 203 = ProtocolError | ||
46 | toEnum 204 = MethodUnknown | ||
47 | toEnum _ = GenericError | ||
48 | {-# INLINE toEnum #-} | ||
49 | |||
50 | #ifdef VERSION_bencoding | ||
51 | instance BEncode ErrorCode where | ||
52 | toBEncode = toBEncode . fromEnum | ||
53 | {-# INLINE toBEncode #-} | ||
54 | |||
55 | fromBEncode b = toEnum <$> fromBEncode b | ||
56 | {-# INLINE fromBEncode #-} | ||
57 | #endif | ||
58 | |||
59 | -- | Errors are sent when a query cannot be fulfilled. Error message | ||
60 | -- can be send only from server to client but not in the opposite | ||
61 | -- direction. | ||
62 | -- | ||
63 | data KError tid = KError | ||
64 | { errorCode :: !ErrorCode -- ^ the type of error; | ||
65 | , errorMessage :: !ByteString -- ^ human-readable text message; | ||
66 | , errorId :: !tid -- ^ match to the corresponding 'queryId'. | ||
67 | } deriving ( Show, Eq, Ord, Typeable, Data, Read ) | ||
68 | |||
69 | -- | Errors, or KRPC message dictionaries with a \"y\" value of \"e\", | ||
70 | -- contain one additional key \"e\". The value of \"e\" is a | ||
71 | -- list. The first element is an integer representing the error | ||
72 | -- code. The second element is a string containing the error | ||
73 | -- message. | ||
74 | -- | ||
75 | -- Example Error Packet: | ||
76 | -- | ||
77 | -- > { "t": "aa", "y":"e", "e":[201, "A Generic Error Ocurred"]} | ||
78 | -- | ||
79 | -- or bencoded: | ||
80 | -- | ||
81 | -- > d1:eli201e23:A Generic Error Ocurrede1:t2:aa1:y1:ee | ||
82 | -- | ||
83 | #ifdef VERSION_bencoding | ||
84 | instance (Typeable tid, BEncode tid) => BEncode (KError tid) where | ||
85 | toBEncode KError {..} = toDict $ | ||
86 | "e" .=! (errorCode, errorMessage) | ||
87 | .: "t" .=! errorId | ||
88 | .: "y" .=! ("e" :: ByteString) | ||
89 | .: endDict | ||
90 | {-# INLINE toBEncode #-} | ||
91 | |||
92 | fromBEncode = fromDict $ do | ||
93 | lookAhead $ match "y" (BString "e") | ||
94 | (code, msg) <- field (req "e") | ||
95 | KError code msg <$>! "t" | ||
96 | {-# INLINE fromBEncode #-} | ||
97 | #endif | ||
98 | |||
99 | instance (Typeable tid, Show tid) => Exception (KError tid) | ||
100 | |||
101 | -- | Received 'queryArgs' or 'respVals' can not be decoded. | ||
102 | decodeError :: String -> tid -> KError tid | ||
103 | decodeError msg = KError ProtocolError (Char8.pack msg) | ||
104 | |||
105 | -- | A remote node has send some 'KMessage' this node is unable to | ||
106 | -- decode. | ||
107 | unknownMessage :: Default tid => String -> KError tid | ||
108 | unknownMessage msg = KError ProtocolError (Char8.pack msg) def | ||
109 | |||
110 | |||
diff --git a/src/Network/DatagramServer/Mainline.hs b/src/Network/DatagramServer/Mainline.hs index 70b9b184..17f9dd60 100644 --- a/src/Network/DatagramServer/Mainline.hs +++ b/src/Network/DatagramServer/Mainline.hs | |||
@@ -23,6 +23,8 @@ | |||
23 | {-# LANGUAGE MultiParamTypeClasses #-} | 23 | {-# LANGUAGE MultiParamTypeClasses #-} |
24 | {-# LANGUAGE OverloadedStrings #-} | 24 | {-# LANGUAGE OverloadedStrings #-} |
25 | {-# LANGUAGE TypeSynonymInstances #-} | 25 | {-# LANGUAGE TypeSynonymInstances #-} |
26 | {-# LANGUAGE TypeFamilies #-} | ||
27 | {-# LANGUAGE GeneralizedNewtypeDeriving #-} | ||
26 | module Network.DatagramServer.Mainline | 28 | module Network.DatagramServer.Mainline |
27 | ( -- * Transaction | 29 | ( -- * Transaction |
28 | TransactionId | 30 | TransactionId |
@@ -57,6 +59,9 @@ module Network.DatagramServer.Mainline | |||
57 | , KMessage | 59 | , KMessage |
58 | , KQueryArgs | 60 | , KQueryArgs |
59 | 61 | ||
62 | , NodeId(..) | ||
63 | , nodeIdSize | ||
64 | |||
60 | ) where | 65 | ) where |
61 | 66 | ||
62 | import Control.Applicative | 67 | import Control.Applicative |
@@ -67,12 +72,23 @@ import Data.BEncode as BE | |||
67 | #else | 72 | #else |
68 | import qualified Network.DatagramServer.Tox as Tox | 73 | import qualified Network.DatagramServer.Tox as Tox |
69 | #endif | 74 | #endif |
70 | import Data.ByteString as B | 75 | import Network.DatagramServer.Types |
71 | import Data.ByteString.Char8 as BC | 76 | import Data.Bits |
77 | import Data.ByteString.Base16 as Base16 | ||
78 | import Data.ByteString (ByteString) | ||
79 | import qualified Data.ByteString as BS | ||
80 | import qualified Data.ByteString.Char8 as Char8 | ||
81 | import qualified Data.ByteString.Lazy as L | ||
82 | import Data.Default | ||
83 | import Data.LargeWord | ||
72 | import qualified Data.Serialize as S | 84 | import qualified Data.Serialize as S |
85 | import Data.Serialize (Serialize, get, put, remaining, getBytes, putByteString) | ||
86 | import Data.String | ||
73 | import Data.Word | 87 | import Data.Word |
74 | import Data.Typeable | 88 | import Data.Typeable |
75 | import Network.Socket (SockAddr (..),PortNumber,HostAddress) | 89 | import Network.Socket (SockAddr (..),PortNumber,HostAddress) |
90 | import Text.PrettyPrint as PP hiding ((<>)) | ||
91 | import Text.PrettyPrint.HughesPJClass hiding (($$), (<>)) | ||
76 | 92 | ||
77 | 93 | ||
78 | #ifdef VERSION_bencoding | 94 | #ifdef VERSION_bencoding |
@@ -81,7 +97,7 @@ import Network.Socket (SockAddr (..),PortNumber,HostAddress) | |||
81 | -- multiple queries to the same node. The transaction ID should be | 97 | -- multiple queries to the same node. The transaction ID should be |
82 | -- encoded as a short string of binary numbers, typically 2 characters | 98 | -- encoded as a short string of binary numbers, typically 2 characters |
83 | -- are enough as they cover 2^16 outstanding queries. | 99 | -- are enough as they cover 2^16 outstanding queries. |
84 | type TransactionId = ByteString | 100 | type TransactionId = TransactionID KMessageOf |
85 | #else | 101 | #else |
86 | type TransactionId = Tox.Nonce24 -- msgNonce | 102 | type TransactionId = Tox.Nonce24 -- msgNonce |
87 | #endif | 103 | #endif |
@@ -94,113 +110,6 @@ unknownTransaction = 0 | |||
94 | #endif | 110 | #endif |
95 | 111 | ||
96 | {----------------------------------------------------------------------- | 112 | {----------------------------------------------------------------------- |
97 | -- Error messages | ||
98 | -----------------------------------------------------------------------} | ||
99 | |||
100 | -- | Types of RPC errors. | ||
101 | data ErrorCode | ||
102 | -- | Some error doesn't fit in any other category. | ||
103 | = GenericError | ||
104 | |||
105 | -- | Occur when server fail to process procedure call. | ||
106 | | ServerError | ||
107 | |||
108 | -- | Malformed packet, invalid arguments or bad token. | ||
109 | | ProtocolError | ||
110 | |||
111 | -- | Occur when client trying to call method server don't know. | ||
112 | | MethodUnknown | ||
113 | deriving (Show, Read, Eq, Ord, Bounded, Typeable) | ||
114 | |||
115 | -- | According to the table: | ||
116 | -- <http://bittorrent.org/beps/bep_0005.html#errors> | ||
117 | instance Enum ErrorCode where | ||
118 | fromEnum GenericError = 201 | ||
119 | fromEnum ServerError = 202 | ||
120 | fromEnum ProtocolError = 203 | ||
121 | fromEnum MethodUnknown = 204 | ||
122 | {-# INLINE fromEnum #-} | ||
123 | |||
124 | toEnum 201 = GenericError | ||
125 | toEnum 202 = ServerError | ||
126 | toEnum 203 = ProtocolError | ||
127 | toEnum 204 = MethodUnknown | ||
128 | toEnum _ = GenericError | ||
129 | {-# INLINE toEnum #-} | ||
130 | |||
131 | #ifdef VERSION_bencoding | ||
132 | instance BEncode ErrorCode where | ||
133 | toBEncode = toBEncode . fromEnum | ||
134 | {-# INLINE toBEncode #-} | ||
135 | |||
136 | fromBEncode b = toEnum <$> fromBEncode b | ||
137 | {-# INLINE fromBEncode #-} | ||
138 | #endif | ||
139 | |||
140 | #ifdef VERSION_bencoding | ||
141 | -- | Errors are sent when a query cannot be fulfilled. Error message | ||
142 | -- can be send only from server to client but not in the opposite | ||
143 | -- direction. | ||
144 | -- | ||
145 | data KError = KError | ||
146 | { errorCode :: !ErrorCode -- ^ the type of error; | ||
147 | , errorMessage :: !ByteString -- ^ human-readable text message; | ||
148 | , errorId :: !TransactionId -- ^ match to the corresponding 'queryId'. | ||
149 | } deriving ( Show, Eq, Ord, Typeable, Read ) | ||
150 | #else | ||
151 | type KError = Tox.Message ByteString -- TODO TOX unused | ||
152 | #endif | ||
153 | |||
154 | -- | Errors, or KRPC message dictionaries with a \"y\" value of \"e\", | ||
155 | -- contain one additional key \"e\". The value of \"e\" is a | ||
156 | -- list. The first element is an integer representing the error | ||
157 | -- code. The second element is a string containing the error | ||
158 | -- message. | ||
159 | -- | ||
160 | -- Example Error Packet: | ||
161 | -- | ||
162 | -- > { "t": "aa", "y":"e", "e":[201, "A Generic Error Ocurred"]} | ||
163 | -- | ||
164 | -- or bencoded: | ||
165 | -- | ||
166 | -- > d1:eli201e23:A Generic Error Ocurrede1:t2:aa1:y1:ee | ||
167 | -- | ||
168 | #ifdef VERSION_bencoding | ||
169 | instance BEncode KError where | ||
170 | toBEncode KError {..} = toDict $ | ||
171 | "e" .=! (errorCode, errorMessage) | ||
172 | .: "t" .=! errorId | ||
173 | .: "y" .=! ("e" :: ByteString) | ||
174 | .: endDict | ||
175 | {-# INLINE toBEncode #-} | ||
176 | |||
177 | fromBEncode = fromDict $ do | ||
178 | lookAhead $ match "y" (BString "e") | ||
179 | (code, msg) <- field (req "e") | ||
180 | KError code msg <$>! "t" | ||
181 | {-# INLINE fromBEncode #-} | ||
182 | #endif | ||
183 | |||
184 | instance Exception KError | ||
185 | |||
186 | -- | Received 'queryArgs' or 'respVals' can not be decoded. | ||
187 | decodeError :: String -> TransactionId -> KError | ||
188 | #ifdef VERSION_bencoding | ||
189 | decodeError msg = KError ProtocolError (BC.pack msg) | ||
190 | #else | ||
191 | decodeError msg = error "TODO TOX Error packet" | ||
192 | #endif | ||
193 | |||
194 | -- | A remote node has send some 'KMessage' this node is unable to | ||
195 | -- decode. | ||
196 | unknownMessage :: String -> KError | ||
197 | #ifdef VERSION_bencoding | ||
198 | unknownMessage msg = KError ProtocolError (BC.pack msg) unknownTransaction | ||
199 | #else | ||
200 | unknownMessage msg = error "TODO TOX Protocol error" | ||
201 | #endif | ||
202 | |||
203 | {----------------------------------------------------------------------- | ||
204 | -- Query messages | 113 | -- Query messages |
205 | -----------------------------------------------------------------------} | 114 | -----------------------------------------------------------------------} |
206 | 115 | ||
@@ -259,21 +168,18 @@ queryMethod = Tox.msgType | |||
259 | queryId = Tox.msgNonce | 168 | queryId = Tox.msgNonce |
260 | #endif | 169 | #endif |
261 | 170 | ||
262 | newtype ReflectedIP = ReflectedIP SockAddr | ||
263 | deriving (Eq, Ord, Show) | ||
264 | |||
265 | port16 :: Word16 -> PortNumber | 171 | port16 :: Word16 -> PortNumber |
266 | port16 = fromIntegral | 172 | port16 = fromIntegral |
267 | 173 | ||
268 | decodeAddr :: ByteString -> Either String SockAddr | 174 | decodeAddr :: ByteString -> Either String SockAddr |
269 | decodeAddr bs | B.length bs == 6 | 175 | decodeAddr bs | BS.length bs == 6 |
270 | = ( \(a,p) -> SockAddrInet <$> fmap port16 p <*> a ) | 176 | = ( \(a,p) -> SockAddrInet <$> fmap port16 p <*> a ) |
271 | $ (S.runGet S.getWord32host *** S.decode ) | 177 | $ (S.runGet S.getWord32host *** S.decode ) |
272 | $ B.splitAt 4 bs | 178 | $ BS.splitAt 4 bs |
273 | decodeAddr bs | B.length bs == 18 | 179 | decodeAddr bs | BS.length bs == 18 |
274 | = ( \(a,p) -> flip SockAddrInet6 0 <$> fmap port16 p <*> a <*> pure 0 ) | 180 | = ( \(a,p) -> flip SockAddrInet6 0 <$> fmap port16 p <*> a <*> pure 0 ) |
275 | $ (S.decode *** S.decode ) | 181 | $ (S.decode *** S.decode ) |
276 | $ B.splitAt 16 bs | 182 | $ BS.splitAt 16 bs |
277 | decodeAddr _ = Left "incorrectly sized address and port" | 183 | decodeAddr _ = Left "incorrectly sized address and port" |
278 | 184 | ||
279 | encodeAddr :: SockAddr -> ByteString | 185 | encodeAddr :: SockAddr -> ByteString |
@@ -281,7 +187,7 @@ encodeAddr (SockAddrInet port addr) | |||
281 | = S.runPut (S.putWord32host addr >> S.put (fromIntegral port :: Word16)) | 187 | = S.runPut (S.putWord32host addr >> S.put (fromIntegral port :: Word16)) |
282 | encodeAddr (SockAddrInet6 port _ addr _) | 188 | encodeAddr (SockAddrInet6 port _ addr _) |
283 | = S.runPut (S.put addr >> S.put (fromIntegral port :: Word16)) | 189 | = S.runPut (S.put addr >> S.put (fromIntegral port :: Word16)) |
284 | encodeAddr _ = B.empty | 190 | encodeAddr _ = BS.empty |
285 | 191 | ||
286 | {----------------------------------------------------------------------- | 192 | {----------------------------------------------------------------------- |
287 | -- Response messages | 193 | -- Response messages |
@@ -345,7 +251,7 @@ respIP = Nothing :: Maybe ReflectedIP | |||
345 | data KMessageOf a | 251 | data KMessageOf a |
346 | = Q (KQueryOf a) | 252 | = Q (KQueryOf a) |
347 | | R (KResponseOf a) | 253 | | R (KResponseOf a) |
348 | | E KError | 254 | | E (KError TransactionId) |
349 | deriving (Show, Eq, Functor, Foldable, Traversable) | 255 | deriving (Show, Eq, Functor, Foldable, Traversable) |
350 | 256 | ||
351 | type KMessage = KMessageOf KQueryArgs | 257 | type KMessage = KMessageOf KQueryArgs |
@@ -364,3 +270,95 @@ instance BEncode KMessage where | |||
364 | type KMessageOf = Tox.Message | 270 | type KMessageOf = Tox.Message |
365 | type KMessage = KMessageOf B.ByteString | 271 | type KMessage = KMessageOf B.ByteString |
366 | #endif | 272 | #endif |
273 | |||
274 | nodeIdSize :: Int | ||
275 | nodeIdSize = finiteBitSize (undefined :: NodeId KMessageOf) `div` 8 | ||
276 | |||
277 | instance BEncode (NodeId KMessageOf) where | ||
278 | toBEncode (NodeId w) = toBEncode $ S.encode w | ||
279 | fromBEncode bval = fromBEncode bval >>= S.decode | ||
280 | |||
281 | -- instance BEncode NodeId where TODO | ||
282 | |||
283 | -- TODO: put this somewhere appropriate | ||
284 | instance (Serialize a, Serialize b) => Serialize (LargeKey a b) where | ||
285 | put (LargeKey lo hi) = put hi >> put lo | ||
286 | get = flip LargeKey <$> get <*> get | ||
287 | |||
288 | instance Serialize (NodeId KMessageOf) where | ||
289 | get = NodeId <$> get | ||
290 | {-# INLINE get #-} | ||
291 | put (NodeId bs) = put bs | ||
292 | {-# INLINE put #-} | ||
293 | |||
294 | -- | ASCII encoded. | ||
295 | instance IsString (NodeId KMessageOf) where | ||
296 | fromString str | ||
297 | | length str == nodeIdSize = NodeId (either error id $ S.decode (fromString str :: ByteString)) | ||
298 | | length str == 2 * nodeIdSize = NodeId (either error id $ S.decode (fst $ Base16.decode $ fromString str)) | ||
299 | | otherwise = error "fromString: invalid NodeId length" | ||
300 | {-# INLINE fromString #-} | ||
301 | |||
302 | -- | Meaningless node id, for testing purposes only. | ||
303 | instance Default (NodeId KMessageOf) where | ||
304 | def = NodeId 0 | ||
305 | |||
306 | -- | base16 encoded. | ||
307 | instance Pretty (NodeId KMessageOf) where | ||
308 | pPrint (NodeId nid) = PP.text $ Char8.unpack $ Base16.encode $ S.encode nid | ||
309 | |||
310 | |||
311 | instance Serialize (TransactionID KMessageOf) where | ||
312 | get = do | ||
313 | cnt <- remaining | ||
314 | TID <$> getBytes cnt | ||
315 | |||
316 | put (TID bs) = putByteString bs | ||
317 | |||
318 | |||
319 | instance Envelope KMessageOf where | ||
320 | type QueryMethod KMessageOf = ByteString | ||
321 | |||
322 | newtype TransactionID KMessageOf = TID ByteString | ||
323 | deriving (Eq,Ord,IsString,Show,Read,BEncode) | ||
324 | |||
325 | -- | Each node has a globally unique identifier known as the \"node | ||
326 | -- ID.\" | ||
327 | -- | ||
328 | -- Normally, /this/ node id should be saved between invocations | ||
329 | -- of the client software. | ||
330 | newtype NodeId KMessageOf = NodeId Word160 | ||
331 | deriving (Show, Eq, Ord, Typeable, Bits, FiniteBits) | ||
332 | |||
333 | envelopePayload (Q q) = queryArgs q | ||
334 | envelopePayload (R r) = respVals r | ||
335 | envelopePayload (E _) = error "TODO: messagePayload for KError" | ||
336 | |||
337 | envelopeTransaction (Q q) = queryId q | ||
338 | envelopeTransaction (R r) = respId r | ||
339 | envelopeTransaction (E e) = errorId e | ||
340 | |||
341 | envelopeClass (Q q) = Query (queryMethod q) | ||
342 | envelopeClass (R r) = Response (respIP r) | ||
343 | envelopeClass (E e) = Error e | ||
344 | |||
345 | buildReply self addr qry response = | ||
346 | (R (KResponse response (envelopeTransaction qry) (Just $ ReflectedIP addr))) | ||
347 | |||
348 | buildQuery self addr meth tid qry = return $ Q (KQuery qry meth tid) | ||
349 | |||
350 | uniqueTransactionId cnt = return $ TID $ Char8.pack (show cnt) | ||
351 | |||
352 | instance WireFormat BValue KMessageOf where | ||
353 | type SerializableTo BValue = BEncode | ||
354 | type CipherContext BValue KMessageOf = () | ||
355 | |||
356 | parsePacket _ = BE.decode | ||
357 | |||
358 | buildError = Just . E | ||
359 | |||
360 | decodeHeaders _ = BE.fromBEncode | ||
361 | decodePayload kmsg = mapM BE.fromBEncode kmsg | ||
362 | |||
363 | encodeHeaders _ kmsg = L.toStrict $ BE.encode kmsg | ||
364 | encodePayload msg = fmap BE.toBEncode msg | ||
diff --git a/src/Network/DatagramServer/Tox.hs b/src/Network/DatagramServer/Tox.hs index ad376c68..2f48b512 100644 --- a/src/Network/DatagramServer/Tox.hs +++ b/src/Network/DatagramServer/Tox.hs | |||
@@ -15,6 +15,9 @@ module Network.DatagramServer.Tox where | |||
15 | 15 | ||
16 | import Data.Bits | 16 | import Data.Bits |
17 | import Data.ByteString (ByteString) | 17 | import Data.ByteString (ByteString) |
18 | import qualified Data.Serialize as S | ||
19 | import qualified Data.ByteString.Lazy as L | ||
20 | import qualified Data.ByteString.Char8 as Char8 | ||
18 | import Data.Data (Data) | 21 | import Data.Data (Data) |
19 | import Data.Word | 22 | import Data.Word |
20 | import Data.LargeWord | 23 | import Data.LargeWord |
@@ -253,7 +256,9 @@ curve25519 = CurveFP (CurvePrime prime curvecommon) | |||
253 | 256 | ||
254 | 257 | ||
255 | instance Envelope Message where | 258 | instance Envelope Message where |
256 | type TransactionID Message = Nonce24 | 259 | newtype TransactionID Message = TID Nonce24 |
260 | deriving (Eq,Ord,Show,Read,Serialize) | ||
261 | |||
257 | newtype NodeId Message = NodeId Word256 | 262 | newtype NodeId Message = NodeId Word256 |
258 | deriving (Serialize, Eq, Ord, Bits, FiniteBits) | 263 | deriving (Serialize, Eq, Ord, Bits, FiniteBits) |
259 | 264 | ||
@@ -268,6 +273,10 @@ instance Envelope Message where | |||
268 | 273 | ||
269 | buildReply self addr qry payload = (fmap (const payload) qry) { msgClient = self } | 274 | buildReply self addr qry payload = (fmap (const payload) qry) { msgClient = self } |
270 | 275 | ||
276 | uniqueTransactionId cnt = do | ||
277 | return $ either (error "failed to create TransactionId") TID | ||
278 | $ S.decode $ Char8.pack (L.take 24 $ show cur ++ L.repeat ' ') | ||
279 | |||
271 | instance WireFormat ByteString Message where | 280 | instance WireFormat ByteString Message where |
272 | type SerializableTo ByteString = Serialize | 281 | type SerializableTo ByteString = Serialize |
273 | type CipherContext ByteString Message = ToxCipherContext | 282 | type CipherContext ByteString Message = ToxCipherContext |
diff --git a/src/Network/DatagramServer/Types.hs b/src/Network/DatagramServer/Types.hs index ac18e6ce..9c8f3ded 100644 --- a/src/Network/DatagramServer/Types.hs +++ b/src/Network/DatagramServer/Types.hs | |||
@@ -3,6 +3,7 @@ | |||
3 | {-# LANGUAGE DeriveFunctor #-} | 3 | {-# LANGUAGE DeriveFunctor #-} |
4 | {-# LANGUAGE DeriveFoldable #-} | 4 | {-# LANGUAGE DeriveFoldable #-} |
5 | {-# LANGUAGE DeriveTraversable #-} | 5 | {-# LANGUAGE DeriveTraversable #-} |
6 | {-# LANGUAGE DefaultSignatures #-} | ||
6 | {-# LANGUAGE FlexibleInstances #-} | 7 | {-# LANGUAGE FlexibleInstances #-} |
7 | {-# LANGUAGE FlexibleContexts #-} | 8 | {-# LANGUAGE FlexibleContexts #-} |
8 | {-# LANGUAGE FunctionalDependencies #-} | 9 | {-# LANGUAGE FunctionalDependencies #-} |
@@ -11,7 +12,10 @@ | |||
11 | {-# LANGUAGE ScopedTypeVariables #-} | 12 | {-# LANGUAGE ScopedTypeVariables #-} |
12 | {-# LANGUAGE TypeFamilies #-} | 13 | {-# LANGUAGE TypeFamilies #-} |
13 | {-# LANGUAGE StandaloneDeriving #-} | 14 | {-# LANGUAGE StandaloneDeriving #-} |
14 | module Network.DatagramServer.Types where | 15 | module Network.DatagramServer.Types |
16 | ( module Network.DatagramServer.Types | ||
17 | , module Network.DatagramServer.Error | ||
18 | ) where | ||
15 | 19 | ||
16 | import Control.Applicative | 20 | import Control.Applicative |
17 | import qualified Text.ParserCombinators.ReadP as RP | 21 | import qualified Text.ParserCombinators.ReadP as RP |
@@ -37,6 +41,7 @@ import qualified Data.ByteString.Char8 as Char8 | |||
37 | import qualified Data.ByteString as BS | 41 | import qualified Data.ByteString as BS |
38 | import Data.ByteString.Base16 as Base16 | 42 | import Data.ByteString.Base16 as Base16 |
39 | import System.Entropy | 43 | import System.Entropy |
44 | import Network.DatagramServer.Error | ||
40 | 45 | ||
41 | class (Eq a, Serialize a, Typeable a, Hashable a, Pretty a) | 46 | class (Eq a, Serialize a, Typeable a, Hashable a, Pretty a) |
42 | => Address a where | 47 | => Address a where |
@@ -69,16 +74,25 @@ instance Address IP where | |||
69 | 74 | ||
70 | 75 | ||
71 | 76 | ||
72 | data MessageClass = Error | Query | Response | 77 | type MessageClass msg = MessageClassG (QueryMethod msg) (TransactionID msg) |
73 | deriving (Eq,Ord,Enum,Bounded,Data,Show,Read) | 78 | |
79 | newtype ReflectedIP = ReflectedIP SockAddr | ||
80 | deriving (Eq, Ord, Show) | ||
81 | |||
82 | data MessageClassG meth tid = Query meth | ||
83 | | Response (Maybe ReflectedIP) | ||
84 | | Error (KError tid) | ||
85 | deriving (Eq,Ord,Show) -- ,Read, Data: not implemented by SockAddr | ||
86 | |||
74 | 87 | ||
75 | class Envelope envelope where | 88 | class Envelope envelope where |
76 | type TransactionID envelope | 89 | data TransactionID envelope |
90 | type QueryMethod envelope | ||
77 | data NodeId envelope | 91 | data NodeId envelope |
78 | 92 | ||
79 | envelopePayload :: envelope a -> a | 93 | envelopePayload :: envelope a -> a |
80 | envelopeTransaction :: envelope a -> TransactionID envelope | 94 | envelopeTransaction :: envelope a -> TransactionID envelope |
81 | envelopeClass :: envelope a -> MessageClass | 95 | envelopeClass :: envelope a -> MessageClass envelope |
82 | 96 | ||
83 | -- | > buildReply self addr qry response | 97 | -- | > buildReply self addr qry response |
84 | -- | 98 | -- |
@@ -93,6 +107,10 @@ class Envelope envelope where | |||
93 | -- Returns: response message envelope | 107 | -- Returns: response message envelope |
94 | buildReply :: NodeId envelope -> SockAddr -> envelope a -> b -> envelope b | 108 | buildReply :: NodeId envelope -> SockAddr -> envelope a -> b -> envelope b |
95 | 109 | ||
110 | buildQuery :: NodeId envelope -> SockAddr -> QueryMethod envelope -> TransactionID envelope -> a -> IO (envelope a) | ||
111 | |||
112 | uniqueTransactionId :: Int -> IO (TransactionID envelope) | ||
113 | |||
96 | -- | In Kademlia, the distance metric is XOR and the result is | 114 | -- | In Kademlia, the distance metric is XOR and the result is |
97 | -- interpreted as an unsigned integer. | 115 | -- interpreted as an unsigned integer. |
98 | newtype NodeDistance nodeid = NodeDistance nodeid | 116 | newtype NodeDistance nodeid = NodeDistance nodeid |
@@ -294,7 +312,15 @@ class Envelope envelope => WireFormat raw envelope where | |||
294 | type SerializableTo raw :: * -> Constraint | 312 | type SerializableTo raw :: * -> Constraint |
295 | type CipherContext raw envelope | 313 | type CipherContext raw envelope |
296 | 314 | ||
297 | decodeHeaders :: CipherContext raw envelope -> ByteString -> Either String (envelope raw) | 315 | parsePacket :: Proxy envelope -> ByteString -> Either String raw |
316 | |||
317 | default parsePacket :: Proxy envelope -> ByteString -> Either String ByteString | ||
318 | parsePacket _ = Right | ||
319 | |||
320 | buildError :: KError (TransactionID envelope) -> Maybe (envelope raw) | ||
321 | buildError _ = Nothing | ||
322 | |||
323 | decodeHeaders :: CipherContext raw envelope -> raw -> Either String (envelope raw) | ||
298 | decodePayload :: SerializableTo raw a => envelope raw -> Either String (envelope a) | 324 | decodePayload :: SerializableTo raw a => envelope raw -> Either String (envelope a) |
299 | 325 | ||
300 | encodeHeaders :: CipherContext raw envelope -> envelope raw -> ByteString | 326 | encodeHeaders :: CipherContext raw envelope -> envelope raw -> ByteString |