/Node.hs

http://github.com/astro/hashvortex · Haskell · 122 lines · 105 code · 15 blank · 2 comment · 6 complexity · 11c4a8a45cb495947ec01ba12aba977d MD5 · raw file

  1. {-# LANGUAGE FlexibleInstances #-}
  2. module Node where
  3. import Control.Concurrent
  4. import qualified Data.ByteString.Lazy.Char8 as B8
  5. import qualified Data.ByteString.Char8 as SB8
  6. import Network.Socket hiding (send, sendTo, recv, recvFrom)
  7. import Network.Socket.ByteString
  8. import Control.Concurrent.Chan
  9. import Control.Monad
  10. import Data.IORef
  11. import qualified Network.Libev as Ev
  12. import Data.Bits ((.&.))
  13. import InState
  14. import KRPC
  15. import BEncoding (BValue)
  16. data NodeState = State { stSock :: Socket,
  17. stQueryHandler :: QueryHandler,
  18. stReplyHandler :: ReplyHandler,
  19. stLastT :: T
  20. }
  21. type Node = IORef NodeState
  22. type QueryHandler = SockAddr -> BValue -> Query -> IO (Either Error Reply)
  23. type ReplyHandler = SockAddr -> BValue -> Reply -> IO ()
  24. new :: Ev.EvLoopPtr -> Int -> IO Node
  25. new evLoop port
  26. = do sock <- socket AF_INET Datagram defaultProtocol
  27. bindSocket sock (SockAddrInet (fromIntegral port) 0)
  28. node <- newIORef State { stSock = sock,
  29. stQueryHandler = nullQueryHandler,
  30. stReplyHandler = nullReplyHandler,
  31. stLastT = T B8.empty
  32. }
  33. let callback evLoop evIo evType
  34. = when (evType .&. Ev.ev_read /= 0) $
  35. runOnce node
  36. fd = fromIntegral $ fdSocket sock
  37. evIoCb <- Ev.mkIoCallback callback
  38. evIo <- Ev.mkEvIo
  39. Ev.evIoInit evIo evIoCb fd Ev.ev_read
  40. Ev.evIoStart evLoop evIo
  41. return node
  42. nullQueryHandler _ _ _
  43. = return $ Left $ Error 201 $ B8.pack "Not implemented"
  44. nullReplyHandler _ _ _
  45. = return ()
  46. setQueryHandler :: QueryHandler -> Node -> IO ()
  47. setQueryHandler cb = inState $ \st -> st { stQueryHandler = cb }
  48. setReplyHandler :: ReplyHandler -> Node -> IO ()
  49. setReplyHandler cb = inState $ \st -> st { stReplyHandler = cb }
  50. run :: Node -> IO ()
  51. run node = do runOnce node
  52. run node
  53. runOnce :: Node -> IO ()
  54. runOnce node = do sock <- stSock `liftM` readIORef node
  55. (buf, addr) <- recvFrom sock 1024
  56. let handle st = catch (handlePacket st buf addr) $ \e ->
  57. do putStrLn $ "Error handling packet: " ++ show e
  58. return st
  59. inState handle node
  60. handlePacket :: NodeState -> SB8.ByteString -> SockAddr -> IO NodeState
  61. handlePacket st buf addr
  62. = do let errorOrPkt = decodePacket buf
  63. case errorOrPkt of
  64. Right (bval, pkt) ->
  65. do --putStrLn $ "Received from " ++ show addr ++ ": " ++ show pkt
  66. let isQuery = case pkt of
  67. (QPacket _ _) -> True
  68. _ -> False
  69. case isQuery of
  70. False ->
  71. case pkt of
  72. RPacket _ reply ->
  73. do catch (stReplyHandler st addr bval reply) print
  74. return st
  75. _ -> return st
  76. True ->
  77. do let QPacket t qry = pkt
  78. qRes <- stQueryHandler st addr bval qry
  79. let pkt = case qRes of
  80. Left e -> EPacket t e
  81. Right r -> RPacket t r
  82. buf = SB8.concat $ B8.toChunks $ encodePacket pkt
  83. --putStrLn $ "Replying " ++ show pkt ++ " to " ++ show addr
  84. catch (sendTo (stSock st) buf addr >>
  85. return ()
  86. ) $ \_ -> return ()
  87. return st
  88. Left e -> do putStrLn e
  89. return st
  90. sendQueryNoWait :: SockAddr -> Query -> Node -> IO ()
  91. sendQueryNoWait addr qry
  92. = inState $ \st ->
  93. do let t = tSucc $ stLastT st
  94. pkt = QPacket t qry
  95. buf = SB8.concat $ B8.toChunks $ encodePacket pkt
  96. putStrLn $ "Sending to " ++ show addr ++ ": " ++ show pkt
  97. catch (sendTo (stSock st) buf addr >>
  98. return ()
  99. ) $ \a -> return ()
  100. return st { stLastT = t }
  101. getAddrs :: String -> String -> IO [SockAddr]
  102. getAddrs name serv
  103. = do putStrLn $ "Resolving " ++ show (name, serv)
  104. liftM (map addrAddress .
  105. filter ((== AF_INET) . addrFamily)) $
  106. getAddrInfo (Just defaultHints { addrFamily = AF_INET })
  107. (Just name) (Just serv)