Revision b172b0ab src/Ganeti/UDSServer.hs
b/src/Ganeti/UDSServer.hs | ||
---|---|---|
1 | 1 |
{-# LANGUAGE TemplateHaskell #-} |
2 |
{-# LANGUAGE FlexibleContexts #-} |
|
2 | 3 |
|
3 | 4 |
{-| Implementation of the Ganeti Unix Domain Socket JSON server interface. |
4 | 5 |
|
... | ... | |
56 | 57 |
) where |
57 | 58 |
|
58 | 59 |
import Control.Applicative |
59 |
import Control.Concurrent (forkIO) |
|
60 |
import Control.Concurrent.Lifted (fork) |
|
61 |
import Control.Monad.Base |
|
62 |
import Control.Monad.Trans.Control |
|
60 | 63 |
import Control.Exception (catch) |
61 | 64 |
import Control.Monad |
62 | 65 |
import qualified Data.ByteString as B |
... | ... | |
198 | 201 |
return Server { sSocket=s, sPath=path, serverConfig=conf } |
199 | 202 |
|
200 | 203 |
-- | Closes a server endpoint. |
201 |
closeServer :: Server -> IO ()
|
|
204 |
closeServer :: (MonadBase IO m) => Server -> m ()
|
|
202 | 205 |
closeServer server = |
203 |
closeServerSocket (sSocket server) (sPath server) |
|
206 |
liftBase $ closeServerSocket (sSocket server) (sPath server)
|
|
204 | 207 |
|
205 | 208 |
-- | Accepts a client |
206 | 209 |
acceptClient :: Server -> IO Client |
... | ... | |
285 | 288 |
-- | Logs an outgoing message. |
286 | 289 |
logMsg |
287 | 290 |
:: (Show e, J.JSON e, MonadLog m) |
288 |
=> Handler i o |
|
291 |
=> Handler i m o
|
|
289 | 292 |
-> i -- ^ the received request (used for logging) |
290 | 293 |
-> GenericResult e J.JSValue -- ^ A message to be sent |
291 | 294 |
-> m () |
... | ... | |
308 | 311 |
|
309 | 312 |
-- * Processing client requests |
310 | 313 |
|
311 |
type HandlerResult o = IO (Bool, GenericResult GanetiException o)
|
|
314 |
type HandlerResult m o = m (Bool, GenericResult GanetiException o)
|
|
312 | 315 |
|
313 |
data Handler i o = Handler |
|
316 |
data Handler i m o = Handler
|
|
314 | 317 |
{ hParse :: J.JSValue -> J.JSValue -> Result i |
315 | 318 |
-- ^ parses method and its arguments into the input type |
316 | 319 |
, hInputLogShort :: i -> String |
317 | 320 |
-- ^ short description of an input, for the INFO logging level |
318 | 321 |
, hInputLogLong :: i -> String |
319 | 322 |
-- ^ long description of an input, for the DEBUG logging level |
320 |
, hExec :: i -> HandlerResult o |
|
323 |
, hExec :: i -> HandlerResult m o
|
|
321 | 324 |
-- ^ executes the handler on an input |
322 | 325 |
} |
323 | 326 |
|
324 | 327 |
|
325 | 328 |
handleJsonMessage |
326 |
:: (J.JSON o) |
|
327 |
=> Handler i o -- ^ handler
|
|
329 |
:: (J.JSON o, Monad m)
|
|
330 |
=> Handler i m o -- ^ handler
|
|
328 | 331 |
-> i -- ^ parsed input |
329 |
-> HandlerResult J.JSValue |
|
332 |
-> HandlerResult m J.JSValue
|
|
330 | 333 |
handleJsonMessage handler req = do |
331 | 334 |
(close, call_result) <- hExec handler req |
332 | 335 |
return (close, fmap J.showJSON call_result) |
... | ... | |
334 | 337 |
-- | Takes a request as a 'String', parses it, passes it to a handler and |
335 | 338 |
-- formats its response. |
336 | 339 |
handleRawMessage |
337 |
:: (J.JSON o) |
|
338 |
=> Handler i o -- ^ handler
|
|
340 |
:: (J.JSON o, MonadLog m)
|
|
341 |
=> Handler i m o -- ^ handler
|
|
339 | 342 |
-> String -- ^ raw unparsed input |
340 |
-> IO (Bool, String)
|
|
343 |
-> m (Bool, String)
|
|
341 | 344 |
handleRawMessage handler payload = |
342 | 345 |
case parseCall payload >>= uncurry (hParse handler) of |
343 | 346 |
Bad err -> do |
... | ... | |
359 | 362 |
-- | Reads a request, passes it to a handler and sends a response back to the |
360 | 363 |
-- client. |
361 | 364 |
handleClient |
362 |
:: (J.JSON o) |
|
363 |
=> Handler i o |
|
365 |
:: (J.JSON o, MonadBase IO m, MonadLog m)
|
|
366 |
=> Handler i m o
|
|
364 | 367 |
-> Client |
365 |
-> IO Bool
|
|
368 |
-> m Bool
|
|
366 | 369 |
handleClient handler client = do |
367 |
msg <- recvMsgExt client |
|
370 |
msg <- liftBase $ recvMsgExt client
|
|
368 | 371 |
|
369 |
debugMode <- isDebugMode |
|
372 |
debugMode <- liftBase isDebugMode
|
|
370 | 373 |
when (debugMode && isRisky msg) $ |
371 | 374 |
logAlert "POSSIBLE LEAKING OF CONFIDENTIAL PARAMETERS. \ |
372 | 375 |
\Daemon is running in debug mode. \ |
... | ... | |
380 | 383 |
return False |
381 | 384 |
RecvOk payload -> do |
382 | 385 |
(close, outMsg) <- handleRawMessage handler payload |
383 |
sendMsg client outMsg |
|
386 |
liftBase $ sendMsg client outMsg
|
|
384 | 387 |
return close |
385 | 388 |
|
386 | 389 |
|
387 | 390 |
-- | Main client loop: runs one loop of 'handleClient', and if that |
388 | 391 |
-- doesn't report a finished (closed) connection, restarts itself. |
389 | 392 |
clientLoop |
390 |
:: (J.JSON o) |
|
391 |
=> Handler i o |
|
393 |
:: (J.JSON o, MonadBase IO m, MonadLog m)
|
|
394 |
=> Handler i m o
|
|
392 | 395 |
-> Client |
393 |
-> IO ()
|
|
396 |
-> m ()
|
|
394 | 397 |
clientLoop handler client = do |
395 | 398 |
result <- handleClient handler client |
396 | 399 |
if result |
397 | 400 |
then clientLoop handler client |
398 |
else closeClient client |
|
401 |
else liftBase $ closeClient client
|
|
399 | 402 |
|
400 | 403 |
-- | Main listener loop: accepts clients, forks an I/O thread to handle |
401 | 404 |
-- that client. |
402 | 405 |
listener |
403 |
:: (J.JSON o) |
|
404 |
=> Handler i o |
|
406 |
:: (J.JSON o, MonadBaseControl IO m, MonadLog m)
|
|
407 |
=> Handler i m o
|
|
405 | 408 |
-> Server |
406 |
-> IO ()
|
|
409 |
-> m ()
|
|
407 | 410 |
listener handler server = do |
408 |
client <- acceptClient server |
|
409 |
_ <- forkIO $ clientLoop handler client
|
|
411 |
client <- liftBase $ acceptClient server
|
|
412 |
_ <- fork $ clientLoop handler client |
|
410 | 413 |
return () |
Also available in: Unified diff