summaryrefslogtreecommitdiff
path: root/src/Network/KRPC/Protocol.hs
diff options
context:
space:
mode:
Diffstat (limited to 'src/Network/KRPC/Protocol.hs')
-rw-r--r--src/Network/KRPC/Protocol.hs81
1 files changed, 1 insertions, 80 deletions
diff --git a/src/Network/KRPC/Protocol.hs b/src/Network/KRPC/Protocol.hs
index 5b072d79..55bbdf4e 100644
--- a/src/Network/KRPC/Protocol.hs
+++ b/src/Network/KRPC/Protocol.hs
@@ -21,45 +21,23 @@
21module Network.KRPC.Protocol 21module Network.KRPC.Protocol
22 ( -- * Error 22 ( -- * Error
23 KError(..) 23 KError(..)
24 , ErrorCode 24 , serverError
25 , errorCode
26 , mkKError
27 25
28 -- * Query 26 -- * Query
29 , KQuery(..) 27 , KQuery(..)
30 , MethodName 28 , MethodName
31 , ParamName
32 29
33 -- * Response 30 -- * Response
34 , KResponse(..) 31 , KResponse(..)
35 , ValName
36
37 , sendMessage
38 , recvResponse
39
40 -- * Remote
41 , withRemote
42 , remoteServer
43 ) where 32 ) where
44 33
45import Control.Applicative
46import Control.Exception.Lifted as Lifted 34import Control.Exception.Lifted as Lifted
47import Control.Monad
48import Control.Monad.IO.Class
49import Control.Monad.Trans.Control
50
51import Data.BEncode as BE 35import Data.BEncode as BE
52import Data.BEncode.BDict as BE 36import Data.BEncode.BDict as BE
53import Data.BEncode.Types as BE
54import Data.ByteString as B 37import Data.ByteString as B
55import Data.ByteString.Char8 as BC 38import Data.ByteString.Char8 as BC
56import qualified Data.ByteString.Lazy as LB
57import Data.Typeable 39import Data.Typeable
58 40
59import Network.Socket hiding (recvFrom)
60import Network.Socket.ByteString
61
62
63-- | Errors used to signal that some error occurred while processing a 41-- | Errors used to signal that some error occurred while processing a
64-- procedure call. Error may be send only from server to client but 42-- procedure call. Error may be send only from server to client but
65-- not in the opposite direction. 43-- not in the opposite direction.
@@ -120,9 +98,7 @@ mkKError _ = GenericError
120serverError :: SomeException -> KError 98serverError :: SomeException -> KError
121serverError = ServerError . BC.pack . show 99serverError = ServerError . BC.pack . show
122 100
123
124type MethodName = ByteString 101type MethodName = ByteString
125type ParamName = ByteString
126 102
127-- | Query used to signal that caller want to make procedure call to 103-- | Query used to signal that caller want to make procedure call to
128-- callee and pass arguments in. Therefore query may be only sent from 104-- callee and pass arguments in. Therefore query may be only sent from
@@ -155,8 +131,6 @@ instance BEncode KQuery where
155 131
156 fromBEncode _ = decodingError "KQuery" 132 fromBEncode _ = decodingError "KQuery"
157 133
158type ValName = ByteString
159
160-- | KResponse used to signal that callee successufully process a 134-- | KResponse used to signal that callee successufully process a
161-- procedure call and to return values from procedure. KResponse should 135-- procedure call and to return values from procedure. KResponse should
162-- not be sent if error occurred during RPC. Thus KResponse may be only 136-- not be sent if error occurred during RPC. Thus KResponse may be only
@@ -183,56 +157,3 @@ instance BEncode KResponse where
183 KResponse <$>! "r" 157 KResponse <$>! "r"
184 158
185 fromBEncode _ = decodingError "KDict" 159 fromBEncode _ = decodingError "KDict"
186
187sockAddrFamily :: SockAddr -> Family
188sockAddrFamily (SockAddrInet _ _ ) = AF_INET
189sockAddrFamily (SockAddrInet6 _ _ _ _) = AF_INET6
190sockAddrFamily (SockAddrUnix _ ) = AF_UNIX
191
192withRemote :: (MonadBaseControl IO m, MonadIO m) => (Socket -> m a) -> m a
193withRemote = bracket (liftIO (socket AF_INET6 Datagram defaultProtocol))
194 (liftIO . sClose)
195{-# SPECIALIZE withRemote :: (Socket -> IO a) -> IO a #-}
196
197maxMsgSize :: Int
198--maxMsgSize = 512 -- release: size of payload of one udp packet
199maxMsgSize = 64 * 1024 -- bench: max UDP MTU
200{-# INLINE maxMsgSize #-}
201
202sendMessage :: BEncode msg => msg -> SockAddr -> Socket -> IO ()
203sendMessage msg addr sock = sendManyTo sock (LB.toChunks (encode msg)) addr
204{-# INLINE sendMessage #-}
205
206recvResponse :: Socket -> IO (Either KError KResponse)
207recvResponse sock = do
208 (raw, _) <- recvFrom sock maxMsgSize
209 return $ case decode raw of
210 Right resp -> Right resp
211 Left decE -> Left $ case decode raw of
212 Right kerror -> kerror
213 _ -> ProtocolError (BC.pack decE)
214
215-- | Run server using a given port. Method invocation should be done manually.
216remoteServer :: (MonadBaseControl IO remote, MonadIO remote)
217 => SockAddr -- ^ Port number to listen.
218 -> (SockAddr -> KQuery -> remote (Either KError KResponse))
219 -> remote ()
220remoteServer servAddr action = bracket (liftIO bindServ) (liftIO . sClose) loop
221 where
222 bindServ = do
223 let family = sockAddrFamily servAddr
224 sock <- socket family Datagram defaultProtocol
225 when (family == AF_INET6) $ do
226 setSocketOption sock IPv6Only 0
227 bindSocket sock servAddr
228 return sock
229
230 loop sock = forever $ do
231 (bs, addr) <- liftIO $ recvFrom sock maxMsgSize
232 reply <- handleMsg bs addr
233 liftIO $ sendMessage reply addr sock
234 where
235 handleMsg bs addr = case decode bs of
236 Right query -> (either toBEncode toBEncode <$> action addr query)
237 `Lifted.catch` (return . toBEncode . serverError)
238 Left decodeE -> return $ toBEncode (ProtocolError (BC.pack decodeE))