]> gitweb @ CieloNegro.org - haskell-dns.git/commitdiff
Response builder
authorPHO <pho@cielonegro.org>
Mon, 25 May 2009 06:38:23 +0000 (15:38 +0900)
committerPHO <pho@cielonegro.org>
Mon, 25 May 2009 06:38:23 +0000 (15:38 +0900)
Network/DNS/Named.hs
Network/DNS/Named/ResponseBuilder.hs [new file with mode: 0644]
Network/DNS/Named/Zone.hs
dns.cabal

index 137bdd52f2994af1f4ab4e350d10f88a820da186..57d9ea4b78b6a765bce5a044444503211c1a8b21 100644 (file)
@@ -15,6 +15,7 @@ import qualified Network.Socket.ByteString as NB
 import           Network.DNS.Message
 import           Network.DNS.Named.Config
 import           Network.DNS.Named.Responder
+import           Network.DNS.Named.ResponseBuilder
 import           Network.DNS.Named.Zone
 import           System.Posix.Signals
 
@@ -56,14 +57,22 @@ runNamed cnf zf
       handleMessage msg
           = case validateQuery msg of
               NoError
-                  -> fail "FIXME: not impl" -- msgQuestions msg
+                  -> do builders <- mapM handleQuestion $ msgQuestions msg
+
+                        let builder = foldl (>>) (return ()) builders
+                            msg'    = runBuilder msg builder
+
+                        return msg'
+
               err -> return $ mkErrorReply err msg
 
-      handleQuestion :: SomeQ -> IO [SomeRR]
+      handleQuestion :: SomeQ -> IO (Builder ())
       handleQuestion (SomeQ q)
-          = do zone       <- findZone zf (qName q)
-               results    <- mapM (runResponder' q) (zoneResponders zone)
-               return $ concat results
+          = do zone    <- findZone zf (qName q)
+               -- FIXME: this is merely a bogus implementation.
+               -- It considers no additional or authoritative sections.
+               results <- mapM (runResponder' q) (zoneResponders zone)
+               return $ mapM_ addAnswer $ concat results
 
 
 validateQuery :: Message -> ResponseCode
diff --git a/Network/DNS/Named/ResponseBuilder.hs b/Network/DNS/Named/ResponseBuilder.hs
new file mode 100644 (file)
index 0000000..487a678
--- /dev/null
@@ -0,0 +1,81 @@
+module Network.DNS.Named.ResponseBuilder
+    ( Builder
+
+    , runBuilder
+
+    , unauthorise
+    , addAnswer
+    , addAuthority
+    , addAdditional
+    )
+    where
+
+import Control.Monad
+import Network.DNS.Message
+
+
+newtype Builder a = B { unB :: Message -> (a, Message) }
+
+instance Monad Builder where
+    return a = B $ \ s -> (a, s)
+    m >>= k  = B $ \ s -> let (a, s') = unB m s
+                          in
+                            unB (k a) s'
+    fail err = B $ error err
+
+
+runBuilder :: Message -> Builder () -> Message
+runBuilder query builder
+    = let initialReply = query {
+                           msgAnswers     = []
+                         , msgAuthorities = []
+                         , msgAdditionals = []
+                         }
+          modHeader'   = modifyHeader $
+                         \ h -> h {
+                                  hdMessageType           = Response
+                                , hdIsAuthoritativeAnswer = True
+                                , hdIsTruncated           = False
+                                , hdIsRecursionAvailable  = False
+                                , hdResponseCode          = NoError
+                                }
+          (_, result)  = unB (modHeader' >> builder) initialReply
+      in
+        result
+
+get :: (Message -> a) -> Builder a
+get f = B $ \ s -> (f s, s)
+
+modify :: (Message -> Message) -> Builder ()
+modify f = B $ \ s -> ((), f s)
+
+modifyHeader :: (Header -> Header) -> Builder ()
+modifyHeader f
+    = modify $ \ s -> s { msgHeader = f (msgHeader s) }
+
+addAnswer :: SomeRR -> Builder ()
+addAnswer rr
+    = do anss <- get msgAnswers
+         unless (any (== rr) anss)
+             $ modify $ \ s ->
+                 s { msgAnswers = msgAnswers s ++ [rr] }
+
+addAuthority :: SomeRR -> Builder ()
+addAuthority rr
+    = do anss <- get msgAnswers
+         aths <- get msgAuthorities
+         unless (any (== rr) anss || any (== rr) aths)
+             $ modify $ \ s ->
+                 s { msgAuthorities = msgAuthorities s ++ [rr] }
+
+addAdditional :: SomeRR -> Builder ()
+addAdditional rr
+    = do anss <- get msgAnswers
+         aths <- get msgAuthorities
+         adds <- get msgAdditionals
+         unless (any (== rr) anss || any (== rr) aths || any (== rr) adds)
+             $ modify $ \ s ->
+                 s { msgAdditionals = msgAdditionals s ++ [rr] }
+
+unauthorise :: Builder ()
+unauthorise = modifyHeader (\ h -> h { hdIsAuthoritativeAnswer = False })
index da27c3e694ab13c669bb5b2d8ee3d0c649fcceae..8311376661bf5b506d951f802234448aab79e677 100644 (file)
@@ -34,4 +34,8 @@ instance ZoneFinder (DomainName -> IO (Maybe Zone)) where
 
 
 defaultRootZone :: Zone
-defaultRootZone = error "FIXME: defaultRootZone is not implemented yet"
\ No newline at end of file
+defaultRootZone
+    = Zone {
+        zoneName       = mkDomainName "."
+      , zoneResponders = [] -- FIXME
+      }
index e55cc17f0c0ec2a111b0c86202b5b822f6fdaf64..7fc84fcde8036f558abf58edaede4886aa566782 100644 (file)
--- a/dns.cabal
+++ b/dns.cabal
@@ -31,6 +31,7 @@ Library
         Network.DNS.Named
         Network.DNS.Named.Config
         Network.DNS.Named.Responder
+        Network.DNS.Named.ResponseBuilder
         Network.DNS.Named.Sanity
         Network.DNS.Named.Zone
         Network.DNS.Packer