Package com.ericsson.ssa.sip.dns

Source Code of com.ericsson.ssa.sip.dns.DnsResolver

/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
* Copyright (c) Ericsson AB, 2004-2008. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License").  You
* may not use this file except in compliance with the License. You can obtain
* a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
* or glassfish/bootstrap/legal/LICENSE.txt.  See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
* Sun designates this particular file as subject to the "Classpath" exception
* as provided by Sun in the GPL Version 2 section of the License file that
* accompanied this code.  If applicable, add the following below the License
* Header, with the fields enclosed by brackets [] replaced by your own
* identifying information: "Portions Copyrighted [year]
* [name of copyright owner]"
*
* Contributor(s):
*
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license."  If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above.  However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*/
package com.ericsson.ssa.sip.dns;

import com.ericsson.ssa.sip.SipFactoryImpl;
import com.ericsson.ssa.sip.SipURIImpl;
import com.ericsson.ssa.sip.UriUtil;
import com.ericsson.ssa.sip.UriUtil.UriUtilException;

import org.glassfish.comms.api.telurl.TelUrlResolver;
import org.glassfish.comms.api.telurl.TelUrlResolverException;
import org.glassfish.comms.api.uriutils.UriTools;

import org.jvnet.glassfish.comms.util.LogUtil;

import org.xbill.DNS.AAAARecord;
import org.xbill.DNS.ARecord;
import org.xbill.DNS.Cache;
import org.xbill.DNS.DClass;
import org.xbill.DNS.Lookup;
import org.xbill.DNS.NAPTRRecord;
import org.xbill.DNS.Name;
import org.xbill.DNS.Record;
import org.xbill.DNS.SRVRecord;
import org.xbill.DNS.TextParseException;
import org.xbill.DNS.Type;

import java.io.IOException;

import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Random;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.servlet.sip.ServletParseException;
import javax.servlet.sip.SipURI;
import javax.servlet.sip.TelURL;
import javax.servlet.sip.URI;


/**
* DNS resolver.
*
* @reviewed qmigkra 2006-oct-12
* @reviewed ejoelbi 2006-nov-07
*/

/**
* @reviewed qmaghes 2007-mars-21
*/
public class DnsResolver implements TelUrlResolver, UriTools {
    private static final Logger logger = LogUtil.SIP_LOGGER.getLogger();
    protected static DnsResolver myInstance = null;
    private Random myRandomInstance = new java.util.Random();
    private TargetFailedRegister myFailedTargets = new TargetFailedRegister();
    private String myEnumTopDomain = "e164.arpa"; // this can be overidden by
    private Translator translator;
    private ConfigurationHandler configurationHandler;
    private final ThreadLocal<List<TargetTuple>> threadLocalFailedRegister = new ThreadLocal<List<TargetTuple>>();

    // preferences or JMX
    public DnsResolver() {
        translator = new Translator();       
        configurationHandler = new ConfigurationHandler(translator);
    }

    public static synchronized DnsResolver getInstance() {
        if (myInstance == null) {
            myInstance = new DnsResolver();
        }

        return myInstance;
    }

    public String normalize(String localPhoneNumber, String phoneContext) {
        return translator.normalize(localPhoneNumber,
                phoneContext);
    }

    public URI canonicalize(URI uri) {
        URI canonicalizedUri = translator.canonicalize(uri);

        return (canonicalizedUri != null) ? canonicalizedUri : uri;
    }

    public void setTargetFailed(TargetTuple target, int expireValue) {
        myFailedTargets.registerFailed(target, expireValue);
    }

    public boolean isTargetFailed(TargetTuple target) {
      List<TargetTuple> localRegister = threadLocalFailedRegister.get();
      if (localRegister != null && localRegister.contains(target)) {
        if (logger.isLoggable(Level.FINEST)) {
          logger.log(Level.FINEST, "skipping target in thread local set " + target);
        }
        return true;
      }
        return myFailedTargets.isFailed(target);
    }
   
    public void setThreadLocalFailedTargets(List<TargetTuple> failedTargets) {
      threadLocalFailedRegister.set(failedTargets);
    }
   
    public void clearThreadLocalFailedTargets() {
      threadLocalFailedRegister.set(null);
    }

    public TargetTuple lookupNameFromSRV(SRVRecord record,
        SipTransports theProtocol)
        throws DnsLookupFailedException, SrvPrioLevelNoValidIpException {
        // orginal
        // TargetTuple.createFromSrv(srv, theProtocol);
        // lookup corresponding A-records
        String srvTarget = record.getTarget().toString(); // String mySRVDomain =
                                                          // record.getTarget().toString();
                                                          // check if srv target is numeric instead of an domain

        if (TargetResolver.isNumericIp(srvTarget)) {
            // the srv record target is an ipadress which has failed
            // lets return a null target (which means that default values might be
            // used
            // for "Selecting SIP Servers".
            // TODO check if an exception should be thrown to the
            // transport layer
            TargetTuple tuple = new TargetTuple(theProtocol, srvTarget,
                    record.getPort());

            if (isTargetFailed(tuple)) {
                return null;
            }

            return tuple;
        }

        String[] ips = lookupNameRecords(srvTarget);

        // first take care of the most frequent (?) case with only 1 A record
        // assigned to the SRV record
        if ((ips.length == 1)) {
            TargetTuple tuple = new TargetTuple(theProtocol, ips[0],
                    record.getPort());

            if (isTargetFailed(tuple)) {
                return null;
            }

            return tuple;
        }

        /*
         * add randomization to distribute among A-records (load balance) however
         * to avoid a possibly INFINITE loop make maximum ips.length attempts to
         * find a suitable target which has not failed otherwise test records
         * sequentially
         */
        int randomIndexToUse = 0;
        int attempts = 0;

        while ((attempts < (ips.length))) {
            attempts++;
            // use a random index (which is not round-robin but which distributes
            // sufficiently)
            randomIndexToUse = getRandomIndex(ips.length);

            String ip = ips[randomIndexToUse];
            TargetTuple tuple = new TargetTuple(theProtocol, ip,
                    record.getPort());

            if (isTargetFailed(tuple) == false) {
                return tuple;
            }
        }

        // did not find a record by random which hasent failed...
        // Lets test records sequentially
        for (int i = 0; i < ips.length; i++) {
            TargetTuple tuple = new TargetTuple(theProtocol, ips[i],
                    record.getPort());

            if (isTargetFailed(tuple) == false) {
                return tuple;
            }
        }

        throw new SrvPrioLevelNoValidIpException(
            "found no valid ip adress for this srv record:" + srvTarget);
    }

    public Record[] doLookup(String domainNameToLookup, int type)
        throws DnsLookupFailedException {
        if (logger.isLoggable(Level.FINE)) {
            logger.log(Level.FINE,
                "doLookup: " + domainNameToLookup + " " + Type.string(type));
            logger.log(Level.FINE,
                "current #cacheentries: " +
                Lookup.getDefaultCache(DClass.IN).getSize());
        }

        // domain need to be fully qualified with new dnsjava version
        if (domainNameToLookup.charAt(domainNameToLookup.length() - 1) != '.') {
            domainNameToLookup += ".";
        }

        Lookup lkup = null;

        try {
            lkup = new Lookup(domainNameToLookup, type);
        } catch (TextParseException e) {
            // we wants only one "checked" exception, lets wrap into a
            // DnsLookupFailedException
            throw new DnsLookupFailedException("Failed to lookup domain:" +
                domainNameToLookup + " error:" + e.getMessage());
        }

        Record[] records = lkup.run();
        int res = lkup.getResult();

        if (res == Lookup.TRY_AGAIN) {
            throw new DnsServerUnavailableException(lkup.getErrorString());
        } else if (lkup.getResult() != Lookup.SUCCESSFUL) {
            throw new DnsLookupFailedException("no such domain:" +
                domainNameToLookup + " error:" + lkup.getErrorString());
        }

        return records;
    }

    public TargetTuple lookupSRVRecord(SipTransports theProtocol,
        String domainNameToLookup) {
        try {
            Record[] records = doLookup(domainNameToLookup, Type.SRV);

            if (logger.isLoggable(Level.FINE)) {
                logger.log(Level.FINE,
                    "number of DNS/SRV records:" + records.length);
            }

            // 1) sort on prio, weight
            java.util.Arrays.sort(records, new SrvComparator());

            // 2) calculate runningSum
            int[] runningSum = new int[records.length];
            int deltaSum = 0;
            int numPriorityGroups = 0;
            int[] priorityGroupBoundaries = new int[records.length];
            int lastPrio = -1;
            int prioIndex = 0;

            for (int i = 0; i < records.length; i++) {
                SRVRecord srv = (SRVRecord) records[i];

                if (srv.getPriority() != lastPrio) {
                    lastPrio = srv.getPriority();
                    deltaSum = 0;
                    priorityGroupBoundaries[prioIndex] = i;
                    prioIndex++;
                    numPriorityGroups++;
                }

                deltaSum += srv.getWeight();
                runningSum[i] = deltaSum;

                //
                if (logger.isLoggable(Level.FINE)) {
                    logger.log(Level.FINE,
                        "SRVRecord.toString():" + srv.toString());
                }

                /*
                 * logger.log(Level.FINE, "SRVRecord.toString():" + srv.toString());
                 * //logger.log(Level.FINE, "Host " + srv.getTarget());
                 * logger.log(Level.FINE, "Priority:"+ srv.getPriority()); logger.log(Level.FINE, "
                 * Weight:"+ srv.getWeight()); logger.log(Level.FINE, " runningSum:"+
                 * runningSum[i]);
                 */
            }

            for (prioIndex = 0; prioIndex < numPriorityGroups; prioIndex++) {
                if (logger.isLoggable(Level.FINE)) {
                    logger.log(Level.FINE, "SRV priolevel:" + prioIndex);
                }

                try {
                    return lookupSRVPrioLevel(prioIndex, theProtocol,
                        runningSum, records, numPriorityGroups,
                        priorityGroupBoundaries);
                } catch (SrvPrioLevelNoValidIpException noValidIPExc) {
                    continue;
                }
            }
        }
        //
        catch (DnsLookupFailedException dLookupEx) {
            if (logger.isLoggable(Level.FINE)) {
                logger.log(Level.FINE, dLookupEx.getMessage());
            }
        }

        if (logger.isLoggable(Level.FINE)) {
            logger.log(Level.FINE,
                "DNS/SRV No record found: " + domainNameToLookup);
        }

        return null;
    }

    public TargetTuple lookupSRVPrioLevel(int prioIndex,
        SipTransports theProtocol, int[] runningSum, Record[] records,
        int numPriorityGroups, int[] priorityGroupBoundaries)
        throws DnsLookupFailedException, SrvPrioLevelNoValidIpException {
        int firstIndex = priorityGroupBoundaries[prioIndex];
        int lastIndex = ((prioIndex + 1) < numPriorityGroups)
            ? (priorityGroupBoundaries[prioIndex + 1] - 1) : (records.length -
            1);
        int maxValue = runningSum[lastIndex] + 1;
        int testValue = getRandomIndex(maxValue);
        int ignoreIndex = -1;

        for (int i = firstIndex; i < (lastIndex + 1); i++) {
            SRVRecord srv = (SRVRecord) records[i];

            // logger.log(Level.FINE, "SRVRecord.toString():" + srv.toString());
            if (runningSum[i] >= testValue) {
                // this is it
                if (logger.isLoggable(Level.FINE)) {
                    logger.log(Level.FINE, "found srv:" + srv.toString());
                }

                TargetTuple targetTuple =
                        lookupNameFromSRV(srv, theProtocol);
                if(targetTuple != null){
                    return targetTuple;
                }
                else{
                    ignoreIndex = i;
                }
            }
        }
        //Since selective lookup failed, iterate over complete list
        for (int i = firstIndex; i < (lastIndex + 1); i++) {
            if(i == ignoreIndex){
                continue;
            }
            SRVRecord srv = (SRVRecord) records[i];

            TargetTuple targetTuple =
                        lookupNameFromSRV(srv, theProtocol);
            if(targetTuple != null){
                return targetTuple;
            }
        }
        throw new SrvPrioLevelNoValidIpException(
                "found no valid ip adress for records with priority "
                + prioIndex);
    }

    //
    public TargetTuple lookupSRVDirect(SipTransports protocol,
        String domainNameToLookup) throws DnsLookupFailedException {
        return lookupSRVDirect(protocol, domainNameToLookup, false);
    }

    public TargetTuple lookupSRVDirect(SipTransports protocol,
        String domainNameToLookup, boolean isUdpMTUExceeded)
        throws DnsLookupFailedException {
        if (isUdpMTUExceeded && (protocol == SipTransports.UDP_PROT)) {
            protocol = SipTransports.TCP_PROT;
        }

        try {
            switch (protocol.ordinal()) {
            case SipTransports.TCP:
            case SipTransports.UDP:
                return lookupSRVRecord(protocol,
                    getSrvDirectLookupId(protocol, domainNameToLookup));

            case SipTransports.UNDEFINED:default: {
                TargetTuple target = null;

                // first try with UDP then TCP if protocol is undefined.
                // we MAY try the protocols we support in any order RFC3263
                // Section
                // 4.1
                if ((isUdpMTUExceeded == false) &&
                        ((target = lookupSRVDirect(SipTransports.UDP_PROT,
                                domainNameToLookup)) != null)) {
                } else if ((target = lookupSRVDirect(SipTransports.TCP_PROT,
                                domainNameToLookup)) != null) {
                }

                return target;
            }
            }
        } catch (DnsLookupFailedException dnfe) {
            return null;
        }
    }

    private String getSrvDirectLookupId(SipTransports protocol,
        String domainNameToLookup) throws DnsLookupFailedException {
        String lookupStr = protocol.getSRVToken() + "." + domainNameToLookup;

        if (logger.isLoggable(Level.FINE)) {
            logger.log(Level.FINE, "getDirectSrvLookupString:" + lookupStr);
        }

        return lookupStr;
    }

    public void clearLocalCache() {
        Cache cache = Lookup.getDefaultCache(DClass.IN);
        cache.clearCache();
    }

    public String lookupName(String domainNameToLookup)
        throws Exception {
        String ip;

        if ((ip = lookupARecord(domainNameToLookup)) != null) {
            return ip;
        } else if ((ip = lookupAAAARecord(domainNameToLookup)) != null) {
            return ip;
        } else {
            return null;
        }
    }

    public String[] lookupNameRecords(String domainNameToLookup)
        throws DnsLookupFailedException {
        String[] ips = null;

        if ((ips = lookupARecords(domainNameToLookup)) != null) {
            return ips;
        } else if ((ips = lookupAAAARecords(domainNameToLookup)) != null) {
            return ips;
        } else {
            return null;
        }
    }

    public String lookupARecord(String domainNameToLookup)
        throws DnsLookupFailedException {
        String[] ips = lookupARecords(domainNameToLookup);

        if (ips == null) {
            return null;
        }

        int indexToUse = 0;

        if ((ips.length > 1)) {
            // we need only to distribute lookups when we have at least 2 A-records
            //
            // use a random index (which is not round-robin but which distributes
            // sufficiently)
            indexToUse = getRandomIndex(ips.length);
        }

        return ips[indexToUse];
    }

    public String[] lookupAAAARecords(String domainNameToLookup)
        throws DnsLookupFailedException {
        try {
            Record[] records = doLookup(domainNameToLookup, Type.AAAA);
            String[] ips = new String[records.length];

            for (int i = 0; i < records.length; i++)
                ips[i] = ((AAAARecord) records[i]).getAddress().getHostAddress();

            return ips;
        } catch (DnsLookupFailedException dLookupEx) {
            if (logger.isLoggable(Level.FINE)) {
                logger.log(Level.FINE, dLookupEx.getMessage());
            }
        }

        if (logger.isLoggable(Level.FINE)) {
            logger.log(Level.FINE,
                "DNS/A No record found: " + domainNameToLookup);
        }

        return null;
    }

    public String[] lookupARecords(String domainNameToLookup)
        throws DnsLookupFailedException {
        try {
            Record[] records = doLookup(domainNameToLookup, Type.A);
            String[] ips = new String[records.length];

            for (int i = 0; i < records.length; i++) //
             {
                ips[i] = ((ARecord) records[i]).getAddress().getHostAddress();
            }

            return ips;
        } catch (DnsLookupFailedException dLookupEx) {
            if (logger.isLoggable(Level.FINE)) {
                logger.log(Level.FINE, dLookupEx.getMessage());
            }
        }

        if (logger.isLoggable(Level.FINE)) {
            logger.log(Level.FINE,
                "DNS/A No record found: " + domainNameToLookup);
        }

        return null;
    }

    public String lookupAAAARecord(String domainNameToLookup)
        throws DnsLookupFailedException {
        try {
            Record[] records = doLookup(domainNameToLookup, Type.AAAA);
            int indexToUse = 0;

            if ((records.length > 1)) {
                // we need only to distribute lookups when we have at least 2
                // A-records
                //
                // use a random index (which is not round-robin but which
                // distributes sufficiently)
                indexToUse = getRandomIndex(records.length);
            }

            return ((AAAARecord) records[indexToUse]).getAddress().getHostAddress();
        } catch (DnsLookupFailedException dLookupEx) {
            if (logger.isLoggable(Level.FINE)) {
                logger.log(Level.FINE, dLookupEx.getMessage());
            }
        }

        if (logger.isLoggable(Level.FINE)) {
            logger.log(Level.FINE,
                "DNS/AAAA No record found: " + domainNameToLookup);
        }

        return null;
    }

    private int getRandomIndex(int upperIndex) {
        int indexToUse = myRandomInstance.nextInt(upperIndex);

        if (logger.isLoggable(Level.FINE)) {
            logger.log(Level.FINE,
                "Picked a random value between 0 and:" + upperIndex +
                " (excl). Random:" + indexToUse);
        }

        return indexToUse;
    }

    public TargetTuple lookupNAPTRRecord(String domainNameToLookup,
        boolean isUdpMTUExceeded) {
        try {
            Record[] records = doLookup(domainNameToLookup, Type.NAPTR);

            if (logger.isLoggable(Level.FINE)) {
                logger.log(Level.FINE,
                    "number of DNS/NAPTR records:" + records.length);
            }

            java.util.Arrays.sort(records, new NaptrComparator());

            // TODO NAPTR: Use the first record we support.
            // from where do we know which protocol this server supports/prefers?
            // NAPTR lookup on this host?
            // (but only within the implemented set (UDP, TCP)
            // Could we assume allways having NAPTR records for own host or
            // should we have an fallback in a "local" config file
            //
            // should we consider other protocol for loadbalancing/fallback
            // --> probably NO
            // I.e. when the protocol to use is decided via NAPTR then we stick
            // with that protocol
            // only exception is MTU size > 1300 bytes etc.
            //
            for (int i = 0; i < records.length; i++) {
                NAPTRRecord record = (NAPTRRecord) records[i];

                if (logger.isLoggable(Level.FINE)) {
                    logger.log(Level.FINE,
                        "NAPTRRecord.toString():" + record.toString());
                }

                String service = record.getService();

                // Lets check the NAPTR record. Do we support the protocol?
                // if MTUExceeded is true UDP should not be considered
                if (SipTransports.UDP_PROT.isSupported() &&
                        service.equals(SipTransports.UDP_PROT.getNAPTRId()) &&
                        (isUdpMTUExceeded == false)) {
                    return lookupSRVRecord(SipTransports.UDP_PROT,
                        record.getReplacement().toString());
                } else if (SipTransports.TCP_PROT.isSupported() &&
                        service.equals(SipTransports.TCP_PROT.getNAPTRId())) {
                    return lookupSRVRecord(SipTransports.TCP_PROT,
                        record.getReplacement().toString());
                }
            }
        } catch (DnsLookupFailedException dLookupEx) {
            if (logger.isLoggable(Level.FINE)) {
                logger.log(Level.FINE, dLookupEx.getMessage());
            }
        }

        if (logger.isLoggable(Level.FINE)) {
            logger.log(Level.FINE,
                "DNS/NAPTR No record found: " + domainNameToLookup);
        }

        return null;
    }

    /*
     * This is the method which implements the interface TelUrlResolver This
     * class maps DnsServerUnavailableException to a IOException
     */
    public SipURI lookupSipURI(URI uri)
        throws TelUrlResolverException, IOException {
        try {
            return doLookupSipURI(uri);
        } catch (DnsServerUnavailableException e) {
            throw new IOException(e.getMessage());
        }
    }

    public boolean isTelephoneNumber(URI uri) {
        return UriUtil.isTelephoneNumber(uri);
    }

    protected SipURI doLookupSipURI(URI uri) throws TelUrlResolverException {
        // validate uri
        if (!isTelephoneNumber(uri)) {
            throw new TelUrlResolverException("The uri is not a phone number:" +
                uri);
        }

        TelURL telUrl = null;

        if (uri.isSipURI()) {
            try {
                telUrl = UriUtil.convertToTelURL((SipURI) uri);
            } catch (UriUtilException e) {
                throw new TelUrlResolverException("Could not convert URI: \"" +
                    uri + "\" to Tel-URL", e);
            }

            if (logger.isLoggable(Level.FINEST)) {
                logger.log(Level.FINEST,
                    "Sip-URI was converted to Tel-URL: " + telUrl);
            }
        } else if (uri.getScheme().equals(SipFactoryImpl.TEL_URI_PROTOCOL)) {
            telUrl = (TelURL) uri;
        }

        String phoneNumber;

        if (telUrl.isGlobal()) {
            phoneNumber = telUrl.getPhoneNumber();
        } else {
            String phoneContext;

            if ((phoneContext = telUrl.getPhoneContext()) == null) {
                throw new TelUrlResolverException("The local number is missing a phone-context: "+telUrl);
            } else {
                phoneNumber = normalize(telUrl.getPhoneNumber(), phoneContext);

                if (phoneNumber == null) {
                    throw new TelUrlResolverException("Could not normalize the phone number: "+telUrl);
                }
                if (logger.isLoggable(Level.FINEST)) {
                    logger.log(Level.FINEST,
                        "The number in the Tel-URL: " + telUrl +
                        " was normalized to " + phoneNumber);
                }
            }
        }

        try {
            String AUS = EnumUtil.getAUSValue(phoneNumber);
            String domainNameToLookup = EnumUtil.toDomain(AUS, myEnumTopDomain);

            return lookupTelUrlNAPTRRecord(AUS, domainNameToLookup,
                new HashSet<String>(), 1);
        } catch (DnsServerUnavailableException dnsue) {
            // All runtime exceptions except DnsServerUnavailableException
            // should be wrapped into a TelUrlResolverException
            throw dnsue;
        } catch (RuntimeException rte) {
            throw new TelUrlResolverException(rte);
        }
    }

    /**
    * @param AUS
    * @param e164arpa_domain
    * @param visited
    * @param depth
    * @return
    */
    protected SipURI lookupTelUrlNAPTRRecord(String AUS,
        String e164arpa_domain, Set<String> visited, int depth)
        throws TelUrlResolverException {
        if ((depth > EnumUtil.MAX_DEPTH) || !visited.add(e164arpa_domain)) {
            throw new TelUrlResolverException("Loop detected when resolving:" +
                AUS);
        }

        if (logger.isLoggable(Level.FINE)) {
            logger.log(Level.FINE,
                "depth:" + depth + " AUS:" + AUS + " domain:" +
                e164arpa_domain);
        }

        try {
            Record[] records = doLookup(e164arpa_domain, Type.NAPTR);
            Arrays.sort(records, new NaptrComparator());

            for (Record record : records) {
                NAPTRRecord naptrRecord = (NAPTRRecord) record;

                if (logger.isLoggable(Level.FINE)) {
                    logger.log(Level.FINE,
                        "number of DNS/NAPTR records:" + records.length);
                    logger.log(Level.FINE,
                        "NAPTRRecord.toString():" + record.toString());
                }

                String flag = naptrRecord.getFlags();
                String service = naptrRecord.getService();
                Name replacement = naptrRecord.getReplacement();

                if (service.equalsIgnoreCase("E2U+sip") ||
                        service.equalsIgnoreCase("sip+E2U")) {
                    if (logger.isLoggable(Level.FINE)) {
                        logger.log(Level.FINE,
                            "flag:" + naptrRecord.getFlags() + " flaglength:" +
                            naptrRecord.getFlags().length());
                        logger.log(Level.FINE,
                            "regexp:" + naptrRecord.getRegexp() +
                            " replacement:" + replacement);
                    }

                    if (!EnumUtil.isEmpty(replacement) && (flag.length() == 0)) {
                        return lookupTelUrlNAPTRRecord(AUS,
                            replacement.toString(), visited, ++depth);
                    }

                    String substitution = EnumUtil.applyRegExp(AUS,
                            naptrRecord.getRegexp());

                    if (substitution == null) {
                        // try next record
                        continue;
                    }

                    if (flag.equals("u")) {
                        int separator = substitution.indexOf(':');

                        if (separator == -1) {
                            throw new TelUrlResolverException(
                                "The regexp substitution result is not any supported uri:" +
                                substitution);
                        }

                        String schemePart = substitution.substring(0, separator);

                        String theUriPart = substitution.substring(separator +
                                1);

                        if (schemePart.equals(SipFactoryImpl.TEL_URI_PROTOCOL)) {
                            return lookupTelUrlNAPTRRecord(AUS,
                                EnumUtil.toDomain(theUriPart, myEnumTopDomain),
                                visited, ++depth);
                        } else if (schemePart.equals(
                                    SipFactoryImpl.SIP_URI_PROTOCOL) ||
                                schemePart.equals(
                                    SipFactoryImpl.SIPS_URI_PROTOCOL)) {
                            try {
                                SipURIImpl sipuri = new SipURIImpl(schemePart,
                                        theUriPart, 0);

                                // check user=phone etc here
                                String userParam = sipuri.getParameter("user");

                                if ((userParam != null) &&
                                        userParam.equals("phone")) {
                                    String userTelUrl = sipuri.getUser();

                                    return lookupTelUrlNAPTRRecord(AUS,
                                        EnumUtil.toDomain(userTelUrl,
                                            myEnumTopDomain), visited, ++depth);
                                }

                                return sipuri;
                            } catch (ServletParseException e) {
                                throw new TelUrlResolverException(e);
                            }
                        } else {
                            throw new TelUrlResolverException(
                                "The regexp substitution result is not any supported uri:" +
                                substitution);
                        }
                    } else if (flag.length() == 0) {
                        return lookupTelUrlNAPTRRecord(AUS, substitution,
                            visited, ++depth);
                    }

                    /* else ignore record */
                }

                /* else ignore record */
            }
        } catch (DnsLookupFailedException dLookupEx) {
            if (logger.isLoggable(Level.FINE)) {
                logger.log(Level.FINE, dLookupEx.getMessage());
            }
        }

        return null;
    }

    public void setEnumTopDomain(String topDomain) {
        myEnumTopDomain = topDomain;
    }

    public String getEnumTopDomain() {
        return myEnumTopDomain;
    }

    public void setDnsCacheSize(int newSize) {
        Cache cache = Lookup.getDefaultCache(DClass.IN);

        synchronized (cache) {
            cache.setMaxEntries(newSize);
        }
    }
}
TOP

Related Classes of com.ericsson.ssa.sip.dns.DnsResolver

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.