# -*- test-case-name: twisted.names.test.test_names -*-
# Copyright (c) 2001-2008 Twisted Matrix Laboratories.
# See LICENSE for details.

"""
Async DNS server

Future plans:
    - Better config file format maybe
    - Make sure to differentiate between different classes
    - notice truncation bit

Important: No additional processing is done on some of the record types.
This violates the most basic RFC and is just plain annoying
for resolvers to deal with.  Fix it.

@author: Jp Calderone
"""

import time

from twisted.internet import protocol
from twisted.names import dns, resolve
from twisted.python import log


class DNSServerFactory(protocol.ServerFactory):
    """
    Server factory and tracker for L{DNSProtocol} connections.  This
    class also provides records for responses to DNS queries.

    @ivar connections: A list of all the connected L{DNSProtocol}
        instances using this object as their controller.
    @type connections: C{list} of L{DNSProtocol}
    """

    protocol = dns.DNSProtocol
    cache = None

    def __init__(self, authorities = None, caches = None, clients = None, verbose = 0):
        resolvers = []
        if authorities is not None:
            resolvers.extend(authorities)
        if caches is not None:
            resolvers.extend(caches)
        if clients is not None:
            resolvers.extend(clients)

        self.canRecurse = not not clients
        self.resolver = resolve.ResolverChain(resolvers)
        self.verbose = verbose
        if caches:
            self.cache = caches[-1]
        self.connections = []


    def buildProtocol(self, addr):
        p = self.protocol(self)
        p.factory = self
        return p


    def connectionMade(self, protocol):
        """
        Track a newly connected L{DNSProtocol}.
        """
        self.connections.append(protocol)


    def connectionLost(self, protocol):
        """
        Stop tracking a no-longer connected L{DNSProtocol}.
        """
        self.connections.remove(protocol)


    def sendReply(self, protocol, message, address):
        if self.verbose > 1:
            s = ' '.join([str(a.payload) for a in message.answers])
            auth = ' '.join([str(a.payload) for a in message.authority])
            add = ' '.join([str(a.payload) for a in message.additional])
            if not s:
                log.msg("Replying with no answers")
            else:
                log.msg("Answers are " + s)
                log.msg("Authority is " + auth)
                log.msg("Additional is " + add)

        if address is None:
            protocol.writeMessage(message)