diff options
author | Sam Truzjan <pxqr.sta@gmail.com> | 2013-12-19 17:18:27 +0400 |
---|---|---|
committer | Sam Truzjan <pxqr.sta@gmail.com> | 2013-12-19 17:18:27 +0400 |
commit | 621c73c849332a9446c6e5b9bcd557b30884b318 (patch) | |
tree | 16e29d593dbe676a229b945d695ab50a7e0c2556 /src/Network/KRPC.hs | |
parent | 8048000a4ce6df959f2fd5f6fd4fe70cff579d15 (diff) |
Move all socket stuff to KRPC module
Diffstat (limited to 'src/Network/KRPC.hs')
-rw-r--r-- | src/Network/KRPC.hs | 66 |
1 files changed, 65 insertions, 1 deletions
diff --git a/src/Network/KRPC.hs b/src/Network/KRPC.hs index d295a965..802cddc5 100644 --- a/src/Network/KRPC.hs +++ b/src/Network/KRPC.hs | |||
@@ -114,17 +114,21 @@ module Network.KRPC | |||
114 | , server | 114 | , server |
115 | ) where | 115 | ) where |
116 | 116 | ||
117 | import Control.Exception | 117 | import Control.Applicative |
118 | import Control.Exception.Lifted as Lifted | ||
119 | import Control.Monad | ||
118 | import Control.Monad.Trans.Control | 120 | import Control.Monad.Trans.Control |
119 | import Control.Monad.IO.Class | 121 | import Control.Monad.IO.Class |
120 | import Data.BEncode as BE | 122 | import Data.BEncode as BE |
121 | import Data.ByteString.Char8 as BC | 123 | import Data.ByteString.Char8 as BC |
124 | import Data.ByteString.Lazy as BL | ||
122 | import Data.List as L | 125 | import Data.List as L |
123 | import Data.Monoid | 126 | import Data.Monoid |
124 | import Data.String | 127 | import Data.String |
125 | import Data.Typeable | 128 | import Data.Typeable |
126 | import Network | 129 | import Network |
127 | import Network.Socket | 130 | import Network.Socket |
131 | import Network.Socket.ByteString as BS | ||
128 | 132 | ||
129 | import Network.KRPC.Protocol | 133 | import Network.KRPC.Protocol |
130 | 134 | ||
@@ -166,6 +170,32 @@ showsMethod (Method name) = | |||
166 | paramsTy = typeOf (impossible :: a) | 170 | paramsTy = typeOf (impossible :: a) |
167 | valuesTy = typeOf (impossible :: b) | 171 | valuesTy = typeOf (impossible :: b) |
168 | 172 | ||
173 | {----------------------------------------------------------------------- | ||
174 | -- Client | ||
175 | -----------------------------------------------------------------------} | ||
176 | |||
177 | sendMessage :: BEncode msg => msg -> SockAddr -> Socket -> IO () | ||
178 | sendMessage msg addr sock = sendManyTo sock (BL.toChunks (encode msg)) addr | ||
179 | {-# INLINE sendMessage #-} | ||
180 | |||
181 | maxMsgSize :: Int | ||
182 | --maxMsgSize = 512 -- release: size of payload of one udp packet | ||
183 | maxMsgSize = 64 * 1024 -- bench: max UDP MTU | ||
184 | {-# INLINE maxMsgSize #-} | ||
185 | |||
186 | recvResponse :: Socket -> IO (Either KError KResponse) | ||
187 | recvResponse sock = do | ||
188 | (raw, _) <- BS.recvFrom sock maxMsgSize | ||
189 | return $ case decode raw of | ||
190 | Right resp -> Right resp | ||
191 | Left decE -> Left $ case decode raw of | ||
192 | Right kerror -> kerror | ||
193 | _ -> ProtocolError (BC.pack decE) | ||
194 | |||
195 | withRemote :: (MonadBaseControl IO m, MonadIO m) => (Socket -> m a) -> m a | ||
196 | withRemote = bracket (liftIO (socket AF_INET6 Datagram defaultProtocol)) | ||
197 | (liftIO . sClose) | ||
198 | {-# SPECIALIZE withRemote :: (Socket -> IO a) -> IO a #-} | ||
169 | 199 | ||
170 | getResult :: BEncode result => Socket -> IO result | 200 | getResult :: BEncode result => Socket -> IO result |
171 | getResult sock = do | 201 | getResult sock = do |
@@ -183,6 +213,10 @@ call addr arg = liftIO $ withRemote $ \sock -> do | |||
183 | where | 213 | where |
184 | Method name = method :: Method req resp | 214 | Method name = method :: Method req resp |
185 | 215 | ||
216 | {----------------------------------------------------------------------- | ||
217 | -- Server | ||
218 | -----------------------------------------------------------------------} | ||
219 | |||
186 | type HandlerBody remote = SockAddr -> KQuery -> remote (Either KError KResponse) | 220 | type HandlerBody remote = SockAddr -> KQuery -> remote (Either KError KResponse) |
187 | 221 | ||
188 | -- | Procedure signature and implementation binded up. | 222 | -- | Procedure signature and implementation binded up. |
@@ -204,6 +238,36 @@ handler body = (name, newbody) | |||
204 | r <- body addr a | 238 | r <- body addr a |
205 | return (Right (KResponse (toBEncode r))) | 239 | return (Right (KResponse (toBEncode r))) |
206 | 240 | ||
241 | sockAddrFamily :: SockAddr -> Family | ||
242 | sockAddrFamily (SockAddrInet _ _ ) = AF_INET | ||
243 | sockAddrFamily (SockAddrInet6 _ _ _ _) = AF_INET6 | ||
244 | sockAddrFamily (SockAddrUnix _ ) = AF_UNIX | ||
245 | |||
246 | -- | Run server using a given port. Method invocation should be done manually. | ||
247 | remoteServer :: (MonadBaseControl IO remote, MonadIO remote) | ||
248 | => SockAddr -- ^ Port number to listen. | ||
249 | -> (SockAddr -> KQuery -> remote (Either KError KResponse)) | ||
250 | -> remote () | ||
251 | remoteServer servAddr action = bracket (liftIO bindServ) (liftIO . sClose) loop | ||
252 | where | ||
253 | bindServ = do | ||
254 | let family = sockAddrFamily servAddr | ||
255 | sock <- socket family Datagram defaultProtocol | ||
256 | when (family == AF_INET6) $ do | ||
257 | setSocketOption sock IPv6Only 0 | ||
258 | bindSocket sock servAddr | ||
259 | return sock | ||
260 | |||
261 | loop sock = forever $ do | ||
262 | (bs, addr) <- liftIO $ BS.recvFrom sock maxMsgSize | ||
263 | reply <- handleMsg bs addr | ||
264 | liftIO $ sendMessage reply addr sock | ||
265 | where | ||
266 | handleMsg bs addr = case decode bs of | ||
267 | Right query -> (either toBEncode toBEncode <$> action addr query) | ||
268 | `Lifted.catch` (return . toBEncode . serverError) | ||
269 | Left decodeE -> return $ toBEncode (ProtocolError (BC.pack decodeE)) | ||
270 | |||
207 | -- | Run RPC server on specified port by using list of handlers. | 271 | -- | Run RPC server on specified port by using list of handlers. |
208 | -- Server will dispatch procedure specified by callee, but note that | 272 | -- Server will dispatch procedure specified by callee, but note that |
209 | -- it will not create new thread for each connection. | 273 | -- it will not create new thread for each connection. |