001/**
002 *
003 * Copyright 2014-2016 Florian Schmaus
004 *
005 * Licensed under the Apache License, Version 2.0 (the "License");
006 * you may not use this file except in compliance with the License.
007 * You may obtain a copy of the License at
008 *
009 *     http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.jivesoftware.smack.util.dns.minidns;
018
019import java.util.LinkedList;
020import java.util.List;
021
022import org.jivesoftware.smack.initializer.SmackInitializer;
023import org.jivesoftware.smack.util.DNSUtil;
024import org.jivesoftware.smack.util.dns.DNSResolver;
025import org.jivesoftware.smack.util.dns.SRVRecord;
026import org.jxmpp.util.cache.ExpirationCache;
027
028import de.measite.minidns.Client;
029import de.measite.minidns.DNSCache;
030import de.measite.minidns.DNSMessage;
031import de.measite.minidns.Question;
032import de.measite.minidns.Record;
033import de.measite.minidns.Record.CLASS;
034import de.measite.minidns.Record.TYPE;
035import de.measite.minidns.record.Data;
036import de.measite.minidns.record.SRV;
037
038
039/**
040 * This implementation uses the <a href="https://github.com/rtreffer/minidns/">minidns</a> implementation for
041 * resolving DNS addresses.
042 */
043public class MiniDnsResolver implements SmackInitializer, DNSResolver {
044
045    private static final long ONE_DAY = 24*60*60*1000;
046    private static final MiniDnsResolver instance = new MiniDnsResolver();
047    private static final ExpirationCache<Question, DNSMessage> cache = new ExpirationCache<Question, DNSMessage>(10, ONE_DAY);
048    private final Client client; 
049
050    public MiniDnsResolver() {
051        client = new Client(new DNSCache() {
052
053            @Override
054            public DNSMessage get(Question question) {
055                return cache.get(question);
056            }
057
058            @Override
059            public void put(Question question, DNSMessage message) {
060                long expirationTime = ONE_DAY;
061                for (Record record : message.getAnswers()) {
062                    if (record.isAnswer(question)) {
063                        expirationTime = record.getTtl();
064                        break;
065                    }
066                }
067                cache.put(question, message, expirationTime);
068            }
069
070        });
071    }
072
073    public static DNSResolver getInstance() {
074        return instance;
075    }
076
077    @Override
078    public List<SRVRecord> lookupSRVRecords(String name) {
079        List<SRVRecord> res = new LinkedList<SRVRecord>();
080        DNSMessage message = client.query(name, TYPE.SRV, CLASS.IN);
081        if (message == null) {
082            return res;
083        }
084        for (Record record : message.getAnswers()) {
085            Data data = record.getPayload();
086            if (!(data instanceof SRV)) {
087                continue;
088            }
089            SRV srv = (SRV) data;
090            res.add(new SRVRecord(srv.getName(), srv.getPort(), srv.getPriority(), srv.getWeight()));
091        }
092        return res;
093    }
094
095    public static void setup() {
096        DNSUtil.setDNSResolver(getInstance());
097    }
098
099    @Override
100    public List<Exception> initialize() {
101        setup();
102        return null;
103    }
104
105}