Package net.windwards.dnsfrontend.frontend

Source Code of net.windwards.dnsfrontend.frontend.ResolveTask

package net.windwards.dnsfrontend.frontend;

import net.sf.ehcache.Ehcache;
import net.sf.ehcache.Element;
import net.windwards.dnsfrontend.api.AbstractTaskKeeper;
import net.windwards.dnsfrontend.api.Backend;
import net.windwards.dnsfrontend.api.BackendCommunicationException;
import net.windwards.dnsfrontend.api.BackendRepository;
import net.windwards.dnsfrontend.api.NoSuchDomainException;
import net.windwards.dnsfrontend.dialog.ProtocolCodingException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xbill.DNS.Flags;
import org.xbill.DNS.Message;
import org.xbill.DNS.NULLRecord;
import org.xbill.DNS.Opcode;
import org.xbill.DNS.Rcode;
import org.xbill.DNS.Record;
import org.xbill.DNS.Section;

import java.io.IOException;


public class ResolveTask implements Runnable {
    private Logger logger = LoggerFactory.getLogger(ResolveTask.class);

    protected final Query query;
    protected Ehcache cache;
    protected AbstractTaskKeeper waitHere;
    protected String ident;
    private BackendRepository backends;

    final private Object DontExist = new Object();

    public ResolveTask(Query query) {
        this.query = query;
    }

    public void setStagingZone(AbstractTaskKeeper zone) {
        this.waitHere = zone;
    }

    public void setCache(Ehcache cache) {
        this.cache = cache;
    }

    public void setBackendStore(BackendRepository backendStore) {
        this.backends = backendStore;
    }

    public String getIdent() {
        return this.ident;
    }

    @Override
    public void run() {
        try {
            this.query.interpret();
        } catch (IOException e) {
            this.fail("Could not parse query");
            return;
        }

        if (this.query.getMessage().getHeader().getOpcode() != Opcode.QUERY) {
            this.refuse();
            return;
        }

        Record question = this.query.getMessage().getQuestion();
        Backend backend = this.backends.lookup(question.getType());

        if (backend == null) {
            this.refuse();
            return;
        }

        this.ident = backend.makeKey(question);

        logger.debug("Checking cache [key={}]", this.ident);

        // check cache
        Element lmnt = this.cache.get(this.getIdent());
        if(lmnt != null) {
            if(lmnt.getObjectValue() == DontExist) {
                this.timeout();
            } else {
                Record record = (Record) lmnt.getObjectValue();
                this.answer(record, true);
            }
            return;
        }

        logger.debug("Asking backend [query={}]", this.query);

        // Park this query awaiting result from backend
        this.waitHere.keep(this);
        try {
            // Notify backend we need an update
            backend.notify(question);
        } catch (NoSuchDomainException e) {
            this.waitHere.discard(this);
            this.unknown();
        } catch (BackendCommunicationException e) {
            this.waitHere.discard(this);
            this.fail("JGroups failure", e);
        } catch (ProtocolCodingException e) {
            this.waitHere.discard(this);
            this.fail("Failed to encode request", e);
        }
    }

    private void processMessage(Message message) {
        try {
            this.query.reply(message);
        } catch (IOException e) {
            logger.warn("Failure sending reply [query={}]", this.query);
        }
    }

    public void answer(Record record, boolean cached)  {
        if(record.getType() != this.query.getMessage().getQuestion().getType()) {
            this.fail("Question/Answer mismatch");
            return;
        }

        Message message = new Message();
        message.getHeader().setFlag(Flags.QR);
        message.getHeader().setFlag(Flags.AA);
        message.addRecord(record, Section.ANSWER);
        String logmsg = cached ? "Cached answer" : "Backend answer";
        logger.info("{} [query={}, record={}]", logmsg, this.query, record);
        this.processMessage(message);
    }

    public void unknown() {
        Message message = new Message();
        message.getHeader().setFlag(Flags.QR);
        message.getHeader().setRcode(Rcode.NXDOMAIN);
        logger.info("Unknown domain [query={}]", this.query);
        this.processMessage(message);
    }

    public void fail(String cause, Throwable... exceptions) {
        Message message = new Message();
        message.getHeader().setFlag(Flags.QR);
        message.getHeader().setRcode(Rcode.SERVFAIL);
        if(exceptions.length == 0) {
            logger.warn("{} [query={}]", cause, this.query);
        } else {
            logger.warn("{} [query={}]", cause, this.query, exceptions[0]);
        }
        this.processMessage(message);
    }

    public void timeout() {
        Message message = new Message();
        message.getHeader().setFlag(Flags.QR);
        message.getHeader().setFlag(Flags.AA);
        message.getHeader().setRcode(Rcode.NXDOMAIN);
        logger.info("No answer [query={}]", this.query);
        this.processMessage(message);
    }

    public void refuse() {
        Message message = new Message();
        message.getHeader().setFlag(Flags.QR);
        message.getHeader().setRcode(Rcode.REFUSED);
        logger.info("Not implemented type [query={}]", this.query);
        this.processMessage(message);
    }
}
TOP

Related Classes of net.windwards.dnsfrontend.frontend.ResolveTask

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.