Source Code Cross Referenced for Resolver.java in  » Apache-Harmony-Java-SE » org-package » org » apache » harmony » jndi » provider » dns » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Apache Harmony Java SE » org package » org.apache.harmony.jndi.provider.dns 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * Licensed to the Apache Software Foundation (ASF) under one or more
0003:         * contributor license agreements.  See the NOTICE file distributed with
0004:         * this work for additional information regarding copyright ownership.
0005:         * The ASF licenses this file to You under the Apache License, Version 2.0
0006:         * (the "License"); you may not use this file except in compliance with
0007:         * the License.  You may obtain a copy of the License at
0008:         *
0009:         *     http://www.apache.org/licenses/LICENSE-2.0
0010:         *
0011:         * Unless required by applicable law or agreed to in writing, software
0012:         * distributed under the License is distributed on an "AS IS" BASIS,
0013:         * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0014:         *
0015:         * See the License for the specific language governing permissions and
0016:         * limitations under the License.
0017:         */
0018:
0019:        /**
0020:         * @author Alexei Y. Zakharov
0021:         * @version $Revision: 1.1.2.5 $
0022:         */package org.apache.harmony.jndi.provider.dns;
0023:
0024:        import java.net.InetAddress;
0025:        import java.net.SocketTimeoutException;
0026:        import java.util.ArrayList;
0027:        import java.util.Enumeration;
0028:        import java.util.HashSet;
0029:        import java.util.Hashtable;
0030:        import java.util.Iterator;
0031:        import java.util.Random;
0032:        import java.util.Set;
0033:        import java.util.StringTokenizer;
0034:        import java.util.Vector;
0035:
0036:        import javax.naming.NameNotFoundException;
0037:        import javax.naming.NamingException;
0038:        import javax.naming.ServiceUnavailableException;
0039:
0040:        import org.apache.harmony.jndi.internal.nls.Messages;
0041:        import org.apache.harmony.jndi.provider.dns.SList.Server;
0042:
0043:        /**
0044:         * This class implements the functionality of a simple DNS resolver.<br>
0045:         * Following DNS Resource Records are supported:
0046:         * <ul>
0047:         * <li>A</li>
0048:         * <li>NS</li>
0049:         * <li>CNAME</li>
0050:         * <li>SOA</li>
0051:         * <li>PTR</li>
0052:         * <li>MX</li>
0053:         * <li>TXT</li>
0054:         * <li>HINFO</li>
0055:         * <li>AAAA (TODO)</li>
0056:         * <li>NAPTR (TODO)</li>
0057:         * <li>SRV</li>
0058:         * </ul>
0059:         * Following DNS classes are supported:
0060:         * <ul>
0061:         * <li>IN</li>
0062:         * <li>HS (TODO)</li>
0063:         * </ul>
0064:         * <br>
0065:         * TODO: do we need broadcasting and IP multicasting to obtain initial name
0066:         * server address? TODO: network-preference feature for choosing most welcome
0067:         * address for multihomed hosts (RFC 1123 point 6.1.3.4) TODO: add general IPv6
0068:         * support and support for AAAA resource record
0069:         */
0070:        public class Resolver implements  Runnable {
0071:
0072:            private static final int MSG_MAX_BYTES = 512;
0073:
0074:            /**
0075:             * Entry of the resolver thread list.
0076:             */
0077:            private static class ThreadListEntry {
0078:                Thread thread;
0079:
0080:                String serverNameToResolve;
0081:
0082:                int dnsClass;
0083:            }
0084:
0085:            private static final Random rndGen = new Random();
0086:
0087:            // resolver configuration
0088:            private int initialTimeout;
0089:
0090:            private int timeoutRetries;
0091:
0092:            private boolean authoritativeAnswerDesired;
0093:
0094:            private boolean recursionDesired;
0095:
0096:            // maximum number of active threads
0097:            private int threadNumberLimit;
0098:
0099:            // vector with currently running Resolver threads
0100:            private final ArrayList<ThreadListEntry> resolverThreads = new ArrayList<ThreadListEntry>();
0101:
0102:            // the list of host names that should be resolved
0103:            private final ArrayList<ThreadListEntry> hostnamesToResolve = new ArrayList<ThreadListEntry>();
0104:
0105:            // semaphore that controls access to both lists above
0106:            private class ThreadListSemaphore {
0107:            }
0108:
0109:            private final Object threadListSemaphore = new ThreadListSemaphore();
0110:
0111:            /**
0112:             * Constructs a <code>Resolver</code> object with default initial timeout
0113:             * (1 second), default timeout retries (4 times), default recursion desired
0114:             * switch (true) and default authoritative answer desired
0115:             * 
0116:             * @see #Resolver(int, int)
0117:             */
0118:            public Resolver() {
0119:                this (ProviderConstants.DEFAULT_INITIAL_TIMEOUT,
0120:                        ProviderConstants.DEFAULT_TIMEOUT_RETRIES,
0121:                        ProviderConstants.DEFAULT_MAX_THREADS,
0122:                        ProviderConstants.DEFAULT_AUTHORITATIVE,
0123:                        ProviderConstants.DEFAULT_RECURSION);
0124:            }
0125:
0126:            /**
0127:             * Constructs a <code>Resolver</code> object with given initial timeout
0128:             * and timeout retries. Initially the resolver will try to access DNS
0129:             * servers with timeout set to initial timeout. If none of servers answer it
0130:             * will double the timeout and perform the second round. The process will
0131:             * continue for <code>timeoutRetries</code> rounds. If there is no answer
0132:             * still the resolver will give up.
0133:             * 
0134:             * @param initialTimeout
0135:             *            the initial timeout that is used during the first round (in
0136:             *            milliseconds)
0137:             * @param timeoutRetries
0138:             *            number of rounds the Resolver should perform before giving up
0139:             * @param authoritativeAnswerDesired
0140:             *            do we want to receive only authoritative answers
0141:             * @param recursionDesired
0142:             *            do we want our outgoing packages to have RD but set
0143:             */
0144:            public Resolver(int initialTimeout, int timeoutRetries,
0145:                    int maxThreads, boolean authoritativeAnswerDesired,
0146:                    boolean recursionDesired) {
0147:                this .initialTimeout = initialTimeout;
0148:                this .timeoutRetries = timeoutRetries;
0149:                this .threadNumberLimit = maxThreads;
0150:                this .authoritativeAnswerDesired = authoritativeAnswerDesired;
0151:                this .recursionDesired = recursionDesired;
0152:            }
0153:
0154:            /**
0155:             * @return Returns the threadNumberLimit.
0156:             */
0157:            public int getThreadNumberLimit() {
0158:                return threadNumberLimit;
0159:            }
0160:
0161:            /**
0162:             * @param threadNumberLimit
0163:             *            The threadNumberLimit to set.
0164:             */
0165:            public void setThreadNumberLimit(int threadNumberLimit) {
0166:                this .threadNumberLimit = threadNumberLimit;
0167:            }
0168:
0169:            /**
0170:             * @return Returns the authoritativeAnswerDesired.
0171:             */
0172:            public boolean isAuthoritativeAnswerDesired() {
0173:                return authoritativeAnswerDesired;
0174:            }
0175:
0176:            /**
0177:             * @param authoritativeAnswerDesired
0178:             *            The authoritativeAnswerDesired to set.
0179:             */
0180:            public void setAuthoritativeAnswerDesired(
0181:                    boolean authoritativeAnswerDesired) {
0182:                this .authoritativeAnswerDesired = authoritativeAnswerDesired;
0183:            }
0184:
0185:            /**
0186:             * @return Returns the initialTimeout.
0187:             */
0188:            public int getInitialTimeout() {
0189:                return initialTimeout;
0190:            }
0191:
0192:            /**
0193:             * @param initialTimeout
0194:             *            The initialTimeout to set.
0195:             */
0196:            public void setInitialTimeout(int initialTimeout) {
0197:                this .initialTimeout = initialTimeout;
0198:            }
0199:
0200:            /**
0201:             * @return Returns the recursionDesired.
0202:             */
0203:            public boolean isRecursionDesired() {
0204:                return recursionDesired;
0205:            }
0206:
0207:            /**
0208:             * @param recursionDesired
0209:             *            The recursionDesired to set.
0210:             */
0211:            public void setRecursionDesired(boolean recursionDesired) {
0212:                this .recursionDesired = recursionDesired;
0213:            }
0214:
0215:            /**
0216:             * @return Returns the timeoutRetries.
0217:             */
0218:            public int getTimeoutRetries() {
0219:                return timeoutRetries;
0220:            }
0221:
0222:            /**
0223:             * @param timeoutRetries
0224:             *            The timeoutRetries to set.
0225:             */
0226:            public void setTimeoutRetries(int timeoutRetries) {
0227:                this .timeoutRetries = timeoutRetries;
0228:            }
0229:
0230:            /**
0231:             * Checks available name servers if they have any resource records related
0232:             * to given name & type & class combination. Standard DNS lookup algorithm
0233:             * is used.
0234:             * 
0235:             * @param name
0236:             *            well-formed domain name
0237:             * @param types
0238:             *            an array of types; only records that have such types will be
0239:             *            returned
0240:             * @param classes
0241:             * @return enumeration with found resource records
0242:             * @throws SecurityException
0243:             *             if the resolver is not allowed to use a network subsystem
0244:             * @throws NameNotFoundException
0245:             *             if authoritative server for desired zone was contacted but
0246:             *             given name has not been found in that zone
0247:             * @throws ServiceUnavailableException
0248:             *             if no authoritative server for desired name was found or all
0249:             *             servers are dead or malfunction
0250:             * @throws DomainProtocolException
0251:             *             if some DNS specific error has occurred
0252:             */
0253:            public Enumeration<ResourceRecord> lookup(String name, int[] types,
0254:                    int[] classes) throws SecurityException,
0255:                    NameNotFoundException, ServiceUnavailableException,
0256:                    DomainProtocolException {
0257:
0258:                // Algorithm:
0259:                // 1. Set workZone to the parent of qName; clear queriedServers.
0260:                // 2. Try to get a complete answer for the workZone from the servers
0261:                // currently available in SLIST exclude servers from queriedServers.
0262:                // 3. update queriedServers with "visited servers" info.
0263:                // 4. If the complete answer was received - return it to the user;exit.
0264:                // 5. If the delegation was received:
0265:                // a) If we already have this server & zone pair in SLIST - skip it.
0266:                // b) If we don't have - put it into SLIST
0267:                // c) If we haven't received any new delegations - goto step (7)
0268:                // d) If some new delegation has been received:
0269:                // 1) from delegations: found the zone with the best matching count
0270:                // with qName
0271:                // 2) if this matching count is bigger than matching count between
0272:                // workZone and qName:
0273:                // - set workZone to zone with biggest matching count determined
0274:                // at step (5.d.1)
0275:                // - goto step (2)
0276:                // 3) if it doesn't then goto step 2 with the same workZone
0277:                // 6. If ALIAS was received ...
0278:                // 7. If no answer has been received:
0279:                // a) Check if the workZone is the root zone.
0280:                // b) If so - give up; return empty result to the user.
0281:                // c) If it isn't, set workZone to parent of workZone. Goto step (2).
0282:
0283:                // SList slist = SList.getInstance();
0284:                ResolverCache cache = ResolverCache.getInstance();
0285:
0286:                Vector<QuestionRecord> questions = new Vector<QuestionRecord>();
0287:                Vector<ResourceRecord> answers = new Vector<ResourceRecord>();
0288:
0289:                if (name == null) {
0290:                    // jndi.2E=The name is null
0291:                    throw new NullPointerException(Messages
0292:                            .getString("jndi.2E")); //$NON-NLS-1$
0293:                }
0294:                if (types == null) {
0295:                    // jndi.6B=types is null
0296:                    throw new NullPointerException(Messages
0297:                            .getString("jndi.6B")); //$NON-NLS-1$
0298:                }
0299:                if (classes == null) {
0300:                    // jndi.6C=classes is null
0301:                    throw new NullPointerException(Messages
0302:                            .getString("jndi.6C")); //$NON-NLS-1$
0303:                }
0304:                for (int element : classes) {
0305:                    for (int element0 : types) {
0306:                        QuestionRecord quest = new QuestionRecord(name,
0307:                                element0, element);
0308:                        questions.addElement(quest);
0309:                    }
0310:                }
0311:                // iterate over question records
0312:                for (int i = 0; i < questions.size(); i++) {
0313:                    QuestionRecord curQuestion = questions.elementAt(i);
0314:                    String qName = curQuestion.getQName();
0315:                    Message mesToSend = null;
0316:                    Message receivedMes = null;
0317:                    AnalysisReport report = null;
0318:                    String workZone;
0319:                    Hashtable<Server, Object> visitedServers = new Hashtable<Server, Object>();
0320:
0321:                    // if (LogConst.DEBUG) {
0322:                    // ProviderMgr.logger.fine("Current question: " +
0323:                    // curQuestion.toString());
0324:                    // }
0325:                    // look in cache
0326:                    if (curQuestion.getQType() != ProviderConstants.ANY_QTYPE
0327:                            && curQuestion.getQClass() != ProviderConstants.ANY_QCLASS) {
0328:                        Enumeration<ResourceRecord> recEnum = cache
0329:                                .get(curQuestion);
0330:
0331:                        if (recEnum.hasMoreElements()) {
0332:                            while (recEnum.hasMoreElements()) {
0333:                                answers.addElement(recEnum.nextElement());
0334:                            }
0335:                            // we don't need to query any servers since the information
0336:                            // we want has been found in the local cache
0337:                            // if (LogConst.DEBUG) {
0338:                            // ProviderMgr.logger.fine(
0339:                            // "Information was gathered from cache");
0340:                            // }
0341:                            continue;
0342:                        }
0343:                    }
0344:
0345:                    // query remote DNS servers
0346:
0347:                    // determine work zone
0348:                    if (qName != null && !qName.equals(".")) { //$NON-NLS-1$
0349:                        workZone = qName;
0350:                        // support for SRV-style qNames
0351:                        while (workZone.startsWith("_")) { //$NON-NLS-1$
0352:                            workZone = ProviderMgr.getParentName(workZone);
0353:                        }
0354:                    } else {
0355:                        workZone = "."; //$NON-NLS-1$
0356:                    }
0357:                    // if (LogConst.DEBUG) {
0358:                    // ProviderMgr.logger.fine("Lookup: new workZone is " +
0359:                    // "\"" + workZone + "\"");
0360:                    // }
0361:                    // construct request message
0362:                    try {
0363:                        mesToSend = createMessageForSending(qName, curQuestion
0364:                                .getQType(), curQuestion.getQClass());
0365:                        // if (LogConst.DEBUG) {
0366:                        // ProviderMgr.logger.finest("Message to send:\n" +
0367:                        // mesToSend.toString());
0368:                        // }
0369:
0370:                    } catch (DomainProtocolException e) {
0371:                        throw e;
0372:                    }
0373:                    while (true) {
0374:                        boolean noIdea = false;
0375:
0376:                        try {
0377:                            receivedMes = queryServers(mesToSend, workZone,
0378:                                    visitedServers, false);
0379:                            if (receivedMes != null) {
0380:                                report = analyzeAnswer(mesToSend, receivedMes);
0381:                                if (!report.messageWasTruncated) {
0382:                                    // Put all extra records into the cache for
0383:                                    // future use
0384:                                    for (int k = 0; k < report.extraRecords
0385:                                            .size(); k++) {
0386:                                        ResourceRecord rec = report.extraRecords
0387:                                                .elementAt(k);
0388:
0389:                                        cache.put(rec);
0390:                                    }
0391:                                } else {
0392:                                    // Truncated message MUST NOT be cached and later
0393:                                    // used in such a way that the fact that they are
0394:                                    // truncated is lost (RFC 1123 point 6.1.3.2).
0395:                                }
0396:                                // examine the report
0397:                                if (report.completeAnswerWasReceived) {
0398:                                    // complete answer
0399:                                    // if (LogConst.DEBUG) {
0400:                                    // ProviderMgr.logger.fine(
0401:                                    // "Lookup: a complete answer was received");
0402:                                    // }
0403:                                    for (int k = 0; k < report.records.size(); k++) {
0404:                                        ResourceRecord rec = report.records
0405:                                                .elementAt(k);
0406:                                        answers.addElement(rec);
0407:                                        // we are sure that the answer section has not
0408:                                        // been truncated so we can put the record
0409:                                        // into the cache
0410:                                        cache.put(rec);
0411:                                    }
0412:                                    // exit the loop
0413:                                    break;
0414:                                } else if (report.nameError) {
0415:                                    // name error
0416:                                    // if (LogConst.DEBUG) {
0417:                                    // ProviderMgr.logger.fine("Lookup: name error");
0418:                                    // }
0419:                                    // jndi.6D=Name {0} was not found
0420:                                    throw new NameNotFoundException(Messages
0421:                                            .getString("jndi.6D", name)); //$NON-NLS-1$
0422:                                } else if (report.aliasInfoWasReceived) {
0423:                                    // alias received
0424:                                    // QuestionRecord newQuestion = new
0425:                                    // QuestionRecord();
0426:
0427:                                    // if (LogConst.DEBUG) {
0428:                                    // ProviderMgr.logger.fine(
0429:                                    // "Lookup: an alias was received");
0430:                                    // }
0431:                                    qName = report.newName;
0432:                                    curQuestion.setQName(qName);
0433:                                    // look in cache
0434:                                    if (curQuestion.getQType() != ProviderConstants.ANY_QTYPE
0435:                                            && curQuestion.getQClass() != ProviderConstants.ANY_QCLASS) {
0436:                                        Enumeration<ResourceRecord> recEnum = cache
0437:                                                .get(curQuestion);
0438:
0439:                                        if (recEnum.hasMoreElements()) {
0440:                                            while (recEnum.hasMoreElements()) {
0441:                                                answers.addElement(recEnum
0442:                                                        .nextElement());
0443:                                            }
0444:                                            // We don't need to query any more servers
0445:                                            // since the information we want has been
0446:                                            // found in the local cache.
0447:                                            // Let's switch to next question if any.
0448:                                            break;
0449:                                        }
0450:                                    }
0451:                                    if (qName != null && !qName.equals(".")) //$NON-NLS-1$
0452:                                    {
0453:                                        workZone = qName;
0454:                                    } else {
0455:                                        workZone = "."; //$NON-NLS-1$
0456:                                    }
0457:                                    visitedServers = new Hashtable<Server, Object>();
0458:                                    for (int k = 0; k < report.records.size(); k++) {
0459:                                        answers.addElement(report.records
0460:                                                .elementAt(k));
0461:                                    }
0462:                                    // construct a new request message
0463:                                    try {
0464:                                        mesToSend = createMessageForSending(
0465:                                                qName, curQuestion.getQType(),
0466:                                                curQuestion.getQClass());
0467:                                    } catch (DomainProtocolException e) {
0468:                                        throw e;
0469:                                    }
0470:                                    // if (LogConst.DEBUG) {
0471:                                    // ProviderMgr.logger.fine("Lookup: new name is " +
0472:                                    // "\"" + qName + "\"");
0473:                                    // ProviderMgr.logger.fine(
0474:                                    // "Lookup: new workZone is " +
0475:                                    // "\"" + workZone + "\"");
0476:                                    // }
0477:                                } else if (report.delegationArrived) {
0478:                                    // new delegation, probably need to query once again
0479:                                    int k17 = -1;
0480:                                    int matchingCount = ProviderMgr
0481:                                            .getMatchingCount(qName, workZone);
0482:
0483:                                    // if (LogConst.DEBUG) {
0484:                                    // ProviderMgr.logger.fine(
0485:                                    // "Lookup: delegation arrived");
0486:                                    // }
0487:                                    for (int k = 0; k < report.delegationZones
0488:                                            .size(); k++) {
0489:                                        String curZone = report.delegationZones
0490:                                                .elementAt(k);
0491:                                        int tmpMatchingCount = ProviderMgr
0492:                                                .getMatchingCount(qName,
0493:                                                        curZone);
0494:
0495:                                        if (tmpMatchingCount > matchingCount) {
0496:                                            k17 = k;
0497:                                            matchingCount = tmpMatchingCount;
0498:                                        }
0499:
0500:                                    }
0501:                                    if (k17 != -1) {
0502:                                        // better delegation was received
0503:                                        workZone = report.delegationZones
0504:                                                .elementAt(k17);
0505:                                        // if (LogConst.DEBUG) {
0506:                                        // ProviderMgr.logger.fine(
0507:                                        // "Lookup: better delegation was found");
0508:                                        // }
0509:                                    } else {
0510:                                        // no better delegation
0511:                                        // do nothing, just query the next server of
0512:                                        // the current workZone
0513:                                    }
0514:                                } else {
0515:                                    noIdea = true;
0516:                                }
0517:                            } // end of if report != null block
0518:                            else {
0519:                                noIdea = true;
0520:                            }
0521:                            if (noIdea) {
0522:                                // Resolver has no idea how to get info about
0523:                                // desired host while querying master hosts of the
0524:                                // current workZone.
0525:                                // Let's make one step up to the root.
0526:                                // if (LogConst.DEBUG) {
0527:                                // ProviderMgr.logger.fine("Lookup: no idea");
0528:                                // }
0529:                                if (!workZone.equals(".")) { //$NON-NLS-1$
0530:                                    workZone = ProviderMgr
0531:                                            .getParentName(workZone);
0532:                                    // if (LogConst.DEBUG) {
0533:                                    // ProviderMgr.logger.fine(
0534:                                    // "Lookup: new work zone is " +
0535:                                    // "\"" + workZone + "\"");
0536:                                    // }
0537:                                } else {
0538:                                    // give up
0539:                                    break;
0540:                                    // throw new ServiceUnavailableException(
0541:                                    // "Unable to " +
0542:                                    // "contact authoritative server for " +
0543:                                    // qName +
0544:                                    // " and no other results were found");
0545:                                }
0546:                            }
0547:                        } catch (NameNotFoundException e) {
0548:                            throw e;
0549:                        } catch (DomainProtocolException e) {
0550:                            throw e;
0551:                        }
0552:                    } // query servers loop
0553:
0554:                } // questions loop
0555:                return answers.elements();
0556:            }
0557:
0558:            /**
0559:             * Lists entire DNS zone using zone transfer mechanism.
0560:             * 
0561:             * @param name
0562:             *            DNS zone name
0563:             * @return enumeration with found <code>ResourceRecord</code> objects
0564:             * @throws SecurityException
0565:             *             if the resolver is not allowed to use a network subsystem
0566:             * @throws NameNotFoundException
0567:             *             if authoritative server(s) was not found
0568:             * @throws ServiceUnavailableException
0569:             *             if none of found servers permits zone transfers
0570:             * @throws DomainProtocolException
0571:             *             if some DNS specific error has occured
0572:             */
0573:            public Enumeration<ResourceRecord> list(String name)
0574:                    throws NamingException {
0575:                final int OUT_BUF_SIZE = 512;
0576:                final int IN_BUF_SIZE = 65536;
0577:
0578:                Vector<ResourceRecord> answerVect = new Vector<ResourceRecord>();
0579:                Message mesToSend = null;
0580:                Message receivedMes = null;
0581:                Enumeration<ResourceRecord> enum1;
0582:                // String zoneMasterServer = null;
0583:                // Vector authoritativeServerIPs = new Vector();
0584:                HashSet<Object> authoritativeServers = new HashSet<Object>();
0585:                Iterator<Object> authServersIter;
0586:                int qClassArr[] = new int[1];
0587:                byte outBuf[] = new byte[OUT_BUF_SIZE];
0588:                int outLen;
0589:                byte inBuf[] = new byte[IN_BUF_SIZE];
0590:                boolean received = false;
0591:                boolean completeAnswer = false;
0592:                String proto = null;
0593:
0594:                ResolverCache cache = ResolverCache.getInstance();
0595:                // SList slist = SList.getInstance();
0596:
0597:                if (name == null) {
0598:                    // jndi.2E=The name is null
0599:                    throw new NullPointerException(Messages
0600:                            .getString("jndi.2E")); //$NON-NLS-1$
0601:                }
0602:                // if given name is SRV style name where domain name is prefixed
0603:                // with _Proto
0604:                if (name.startsWith("_")) { //$NON-NLS-1$
0605:                    int n = name.indexOf('.');
0606:
0607:                    if (n != -1) {
0608:                        proto = name.substring(0, n);
0609:                        if (name.length() > n) {
0610:                            name = name.substring(n + 1, name.length());
0611:                        } else {
0612:                            // nonsense
0613:                            name = "."; //$NON-NLS-1$
0614:                        }
0615:                    } else {
0616:                        // nonsense
0617:                        name = "."; //$NON-NLS-1$
0618:                    }
0619:                }
0620:                enum1 = lookup(name, new int[] { ProviderConstants.NS_TYPE },
0621:                        new int[] { ProviderConstants.ANY_QTYPE });
0622:                mesToSend = createMessageForSending(name,
0623:                        ProviderConstants.AXFR_QTYPE,
0624:                        ProviderConstants.ANY_QCLASS);
0625:                outLen = mesToSend.writeBytes(outBuf, 0);
0626:                // determine the list of zone authoritative servers
0627:                while (enum1.hasMoreElements()) {
0628:                    ResourceRecord rr = enum1.nextElement();
0629:
0630:                    if (rr.getRRType() == ProviderConstants.NS_TYPE) {
0631:                        authoritativeServers.add(rr.getRData());
0632:                        // assertion: all authoritative servers should have the same
0633:                        // DNS class
0634:                        qClassArr[0] = rr.getRRClass();
0635:                    } else if (rr.getRRType() == ProviderConstants.SOA_TYPE) {
0636:                        StringTokenizer st = new StringTokenizer((String) rr
0637:                                .getRData(), " "); //$NON-NLS-1$
0638:
0639:                        if (st.hasMoreTokens()) {
0640:                            authoritativeServers.add(st.nextToken());
0641:                            qClassArr[0] = rr.getRRClass();
0642:                            break;
0643:                        }
0644:                    }
0645:                }
0646:                // try to perform a zone transfer
0647:                authServersIter = authoritativeServers.iterator();
0648:                authServersLoop: while (authServersIter.hasNext()) {
0649:                    String authServerName = (String) authServersIter.next();
0650:                    Enumeration<ResourceRecord> addrEnum = lookup(
0651:                            authServerName,
0652:                            new int[] { ProviderConstants.A_TYPE }, qClassArr);
0653:
0654:                    while (addrEnum.hasMoreElements()) {
0655:                        ResourceRecord curRR = addrEnum.nextElement();
0656:                        String ip = (String) curRR.getRData();
0657:
0658:                        try {
0659:                            // if (LogConst.DEBUG) {
0660:                            // ProviderMgr.logger.fine(
0661:                            // "Initiating zone transfer, IP=" + ip);
0662:                            // }
0663:                            TransportMgr.sendReceiveTCP(ip,
0664:                                    ProviderConstants.DEFAULT_DNS_PORT, outBuf,
0665:                                    outLen, inBuf, IN_BUF_SIZE,
0666:                                    this .initialTimeout * this .timeoutRetries);
0667:                            received = true;
0668:                        } catch (SocketTimeoutException e) {
0669:
0670:                            // if (LogConst.DEBUG) {
0671:                            // ProviderMgr.logger.fine("Socket timeout");
0672:                            // }
0673:                        } catch (DomainProtocolException e) {
0674:                            // some problem was encountered
0675:                            // ProviderMgr.logger.log(Level.WARNING,
0676:                            // "Connection failure", e);
0677:                        }
0678:                        if (received) {
0679:                            receivedMes = new Message();
0680:                            try {
0681:                                int rCode;
0682:
0683:                                Message.parseMessage(inBuf, 0, receivedMes);
0684:                                rCode = receivedMes.getRCode();
0685:                                switch (rCode) {
0686:                                case ProviderConstants.NO_ERROR:
0687:                                    // put all received records into Resolver's
0688:                                    // cache
0689:                                    for (int k = 0; k < 3; k++) {
0690:                                        switch (k) {
0691:                                        case 0:
0692:                                            enum1 = receivedMes.getAnswerRRs();
0693:                                            break;
0694:                                        case 1:
0695:                                            enum1 = receivedMes
0696:                                                    .getAuthorityRRs();
0697:                                            break;
0698:                                        case 2:
0699:                                            enum1 = receivedMes
0700:                                                    .getAdditionalRRs();
0701:                                            break;
0702:                                        }
0703:                                        while (enum1.hasMoreElements()) {
0704:                                            ResourceRecord rr = enum1
0705:                                                    .nextElement();
0706:
0707:                                            cache.put(rr);
0708:                                            if (k == 0) {
0709:                                                answerVect.addElement(rr);
0710:                                            }
0711:                                        }
0712:                                    }
0713:                                    completeAnswer = true;
0714:                                    break;
0715:                                case ProviderConstants.NAME_ERROR:
0716:                                    // jndi.6D=Name {0} was not found
0717:                                    throw new NameNotFoundException(Messages
0718:                                            .getString("jndi.6D", name)); //$NON-NLS-1$
0719:                                case ProviderConstants.SERVER_FAILURE:
0720:                                case ProviderConstants.FORMAT_ERROR:
0721:                                case ProviderConstants.NOT_IMPLEMENTED:
0722:                                case ProviderConstants.REFUSED:
0723:                                default:
0724:                                }
0725:                            } catch (DomainProtocolException e) {
0726:                                // ProviderMgr.logger.log(Level.WARNING,
0727:                                // "Error while parsing of DNS message", e);
0728:                            }
0729:                        } // if received
0730:                        if (completeAnswer) {
0731:                            // if (LogConst.DEBUG) {
0732:                            // ProviderMgr.logger.fine(
0733:                            // "list: Complete answer received");
0734:                            // }
0735:                            break authServersLoop;
0736:                        }
0737:                    } // address loop
0738:                } // authoritative servers loop
0739:
0740:                if (!completeAnswer) {
0741:                    // found nothing
0742:                    // jndi.6E=Unable to perform zone transfer
0743:                    throw new ServiceUnavailableException(Messages
0744:                            .getString("jndi.6E")); //$NON-NLS-1$
0745:                }
0746:                // SRV _Proto prefix support - filter all records that don't have given
0747:                // _Proto field
0748:                if (proto != null) {
0749:                    Vector<ResourceRecord> answerVect2 = new Vector<ResourceRecord>();
0750:
0751:                    for (int i = 0; i < answerVect.size(); i++) {
0752:                        ResourceRecord rr = answerVect.elementAt(i);
0753:                        StringTokenizer st = new StringTokenizer(rr.getName(),
0754:                                "."); //$NON-NLS-1$
0755:                        String token = null;
0756:                        boolean valid = false;
0757:
0758:                        if (st.hasMoreTokens()) {
0759:                            token = st.nextToken();
0760:                            if (token.length() > 0 && token.charAt(0) == '_'
0761:                                    && st.hasMoreTokens()) {
0762:                                token = st.nextToken();
0763:                                if (token.equalsIgnoreCase(proto)) {
0764:                                    valid = true;
0765:                                }
0766:                            }
0767:                        }
0768:                        if (valid) {
0769:                            answerVect2.addElement(rr);
0770:                        }
0771:                    }
0772:                    answerVect = answerVect2;
0773:                }
0774:                return answerVect.elements();
0775:            }
0776:
0777:            /**
0778:             * Adds initial DNS server the resolver should start with. Trying underlying
0779:             * OS services to determine IP from name.
0780:             * 
0781:             * @param name
0782:             *            server's name
0783:             * @param ip
0784:             *            server's IP address
0785:             * @param port
0786:             *            port on server
0787:             */
0788:            public void addInitialServer(String name, String ip, int port,
0789:                    String zoneName) {
0790:                SList.Server server = new SList.Server(name, ip, port);
0791:                SList slist = SList.getInstance();
0792:
0793:                if (name == null && ip == null) {
0794:                    // jndi.6F=Both name and IP are null
0795:                    throw new NullPointerException(Messages
0796:                            .getString("jndi.6F")); //$NON-NLS-1$
0797:                }
0798:                if (zoneName == null) {
0799:                    // jndi.70=zoneName is null
0800:                    throw new NullPointerException(Messages
0801:                            .getString("jndi.70")); //$NON-NLS-1$
0802:                }
0803:                // if IP is not given and we don't know this server yet
0804:                // try to determine IP from underlying OS services
0805:                if (ip == null && !slist.hasServer(name)) {
0806:                    InetAddress addrObj = TransportMgr.getIPByName_OS(name);
0807:
0808:                    if (addrObj != null) {
0809:                        server
0810:                                .setIP(ProviderMgr.getIpStr(addrObj
0811:                                        .getAddress()));
0812:                    }
0813:                }
0814:                // add given zone <-> server pair
0815:                if (!slist.hasServer(zoneName, server)) {
0816:                    slist.updateEntry(zoneName, server, SList.UNKNOWN);
0817:                }
0818:            }
0819:
0820:            /**
0821:             * Query available DNS servers for desired information. This method doesn't
0822:             * look into the local cache. Drops all answers that contains "server fail"
0823:             * and "not implemented" answer codes and returns the first "good" answer.
0824:             * 
0825:             * @param request
0826:             *            a DNS message that contains the request record
0827:             * @param workZone
0828:             *            a zone that is closest known (grand-) parent of the desired
0829:             *            name
0830:             * @param visitedServers
0831:             *            the hash list of servers, that should not be examined; this
0832:             *            method also appends to this list all server that have been
0833:             *            visited during execution of this method
0834:             * @param tcpOnly
0835:             *            <code>true</code> if we want to use TCP protocol only;
0836:             *            otherwise UDP will be tried first
0837:             * @return the message received; <code>null</code> if none found
0838:             * @throws DomainProtocolException
0839:             *             some domain protocol related error occured
0840:             * @throws SecurityException
0841:             *             if the resolver doesn't have the permission to use sockets
0842:             */
0843:            Message queryServers(Message request, String workZone,
0844:                    Hashtable<Server, Object> visitedServers, boolean tcpOnly)
0845:                    throws DomainProtocolException, SecurityException {
0846:                QuestionRecord qRecord;
0847:
0848:                SList slist = SList.getInstance();
0849:                SList.Server curServer;
0850:                byte[] outBuf = new byte[MSG_MAX_BYTES];
0851:                int outBufLen;
0852:                byte[] inBuf = new byte[MSG_MAX_BYTES];
0853:                Message receivedMes = null;
0854:                int idx = 0;
0855:                int curTimeout = this .initialTimeout;
0856:                boolean received = false;
0857:                boolean parsed = false;
0858:                boolean correctAnswer = false;
0859:                int rCode = -1;
0860:
0861:                // determine a question
0862:                if (!request.getQuestionRecords().hasMoreElements()) {
0863:                    // jndi.71=no question record
0864:                    throw new IllegalArgumentException(Messages
0865:                            .getString("jndi.71")); //$NON-NLS-1$
0866:                }
0867:                qRecord = request.getQuestionRecords().nextElement();
0868:                // preparing a domain protocol message
0869:                outBufLen = request.writeBytes(outBuf, 0);
0870:
0871:                // sending message and trying to receive an answer
0872:                for (int round = 0; round < this .timeoutRetries; round++) {
0873:                    Set<Server> queriedServers = new HashSet<Server>();
0874:
0875:                    // start of round
0876:                    while (true) {
0877:                        int responseTime = 0;
0878:
0879:                        received = false;
0880:                        parsed = false;
0881:                        rCode = -1;
0882:                        // get next server
0883:                        curServer = slist
0884:                                .getBestGuess(workZone, visitedServers);
0885:                        if (curServer == null
0886:                                || queriedServers.contains(curServer)) {
0887:                            // end of round
0888:                            break;
0889:                        }
0890:                        if (curServer.getIP() == null) {
0891:                            // if we don't know IP lets start background resolving
0892:                            // thread
0893:                            startResolvingThread(curServer.getName(), qRecord
0894:                                    .getQClass());
0895:                            slist.updateEntry(workZone, curServer,
0896:                                    SList.NETWORK_FAILURE);
0897:                            queriedServers.add(curServer);
0898:                            continue;
0899:                        }
0900:                        // send the message and receive the answer
0901:                        try {
0902:                            // if (LogConst.DEBUG) {
0903:                            // ProviderMgr.logger.fine("Timeout is set to " +
0904:                            // curTimeout);
0905:                            // ProviderMgr.logger.fine("Querying server \"" +
0906:                            // curServer + "\"");
0907:                            // }
0908:                            // timeBeforeSending = System.currentTimeMillis();
0909:                            if (tcpOnly) {
0910:                                TransportMgr.sendReceiveTCP(curServer.getIP(),
0911:                                        curServer.getPort(), outBuf, outBufLen,
0912:                                        inBuf, inBuf.length, curTimeout);
0913:                            } else {
0914:                                TransportMgr.sendReceiveUDP(curServer.getIP(),
0915:                                        curServer.getPort(), outBuf, outBufLen,
0916:                                        inBuf, inBuf.length, curTimeout);
0917:                            }
0918:                            // responseTime = (int) (System.currentTimeMillis() -
0919:                            // timeBeforeSending);
0920:                            // ProviderMgr.logger.fine("Answer received in " +
0921:                            // responseTime + " milliseconds");
0922:                            received = true;
0923:                        } catch (SocketTimeoutException e) {
0924:                            slist.updateEntry(workZone, curServer,
0925:                                    SList.TIMEOUT);
0926:                            // if (LogConst.DEBUG) {
0927:                            // ProviderMgr.logger.fine("Socket timeout");
0928:                            // }
0929:                        } catch (DomainProtocolException e) {
0930:                            // problems with receiving the message
0931:                            // skipping this server
0932:                            slist.updateEntry(workZone, curServer,
0933:                                    SList.NETWORK_FAILURE);
0934:                            // ProviderMgr.logger.log(Level.WARNING,
0935:                            // "Connection failure", e);
0936:                        }
0937:                        // parse the message
0938:                        if (received) {
0939:                            try {
0940:                                boolean answerSectionIsTruncated = false;
0941:
0942:                                receivedMes = new Message();
0943:                                idx = 0;
0944:                                idx = Message.parseMessage(inBuf, idx,
0945:                                        receivedMes);
0946:
0947:                                // if (LogConst.DEBUG) {
0948:                                // ProviderMgr.logger.finest("Received message:\n" +
0949:                                // receivedMes.toString());
0950:                                // }
0951:                                parsed = true;
0952:                                // handle a truncation
0953:                                if (receivedMes.isTc() && !tcpOnly) {
0954:                                    // The Message is truncated.
0955:                                    // Let's try to establish a TCP connection
0956:                                    // and retransmit the message over that connection.
0957:                                    // if (LogConst.DEBUG) {
0958:                                    // ProviderMgr.logger.fine("Message is truncated");
0959:                                    // ProviderMgr.logger.fine("Trying to establish " +
0960:                                    // "a connection over TCP");
0961:                                    // }
0962:                                    try {
0963:                                        Message receivedMesTcp;
0964:                                        int idx2;
0965:
0966:                                        TransportMgr.sendReceiveTCP(curServer
0967:                                                .getIP(), curServer.getPort(),
0968:                                                outBuf, outBufLen, inBuf,
0969:                                                inBuf.length, curTimeout);
0970:                                        receivedMesTcp = new Message();
0971:                                        idx2 = Message.parseMessage(inBuf, 0,
0972:                                                receivedMesTcp);
0973:                                        // complete message was received
0974:                                        if (!receivedMesTcp.isTc()) {
0975:                                            receivedMes = receivedMesTcp;
0976:                                            idx = idx2;
0977:                                        }
0978:                                    } catch (Exception e) {
0979:                                        // ProviderMgr.logger.log(Level.WARNING,
0980:                                        // "Receiving a complete message" +
0981:                                        // " over TCP failed", e);
0982:                                        // if (LogConst.DEBUG) {
0983:                                        // ProviderMgr.logger.fine(
0984:                                        // "Parsing the message " +
0985:                                        // "previously received over UDP");
0986:                                        // }
0987:                                    }
0988:                                }
0989:                                // Is the message still truncated?
0990:                                // (It is possible in case if TCP connection failed)
0991:                                if (receivedMes.isTc()) {
0992:                                    // check if the ANSWER section is truncated
0993:                                    // or not
0994:                                    if (!receivedMes.getAuthorityRRs()
0995:                                            .hasMoreElements()
0996:                                            && !receivedMes.getAdditionalRRs()
0997:                                                    .hasMoreElements()) {
0998:                                        answerSectionIsTruncated = true;
0999:                                    }
1000:                                }
1001:                                rCode = receivedMes.getRCode();
1002:                                if (rCode == ProviderConstants.NO_ERROR) {
1003:                                    // correct message has been received
1004:                                    slist.updateEntry(workZone, curServer,
1005:                                            responseTime);
1006:                                    visitedServers.put(curServer, new Object()); // $NON-LOCK-1$
1007:                                    if (!answerSectionIsTruncated) {
1008:                                        correctAnswer = true;
1009:                                        break;
1010:                                    }
1011:                                } else if (rCode == ProviderConstants.SERVER_FAILURE) {
1012:                                    // removing server from list
1013:                                    // ProviderMgr.logger.warning("Server failure. " +
1014:                                    // errMsg);
1015:                                    slist.updateEntry(workZone, curServer,
1016:                                            SList.SERVER_FAILURE);
1017:                                    visitedServers.put(curServer, new Object()); // $NON-LOCK-1$
1018:                                } else if (rCode == ProviderConstants.FORMAT_ERROR) {
1019:                                    // removing server from list
1020:                                    // ProviderMgr.logger.warning("Format error. " +
1021:                                    // errMsg);
1022:                                    slist.updateEntry(workZone, curServer,
1023:                                            SList.SERVER_FAILURE);
1024:                                    visitedServers.put(curServer, new Object()); // $NON-LOCK-1$
1025:                                } else if (rCode == ProviderConstants.NAME_ERROR) {
1026:                                    // ProviderMgr.logger.warning("Name error. " +
1027:                                    // errMsg);
1028:                                    if (receivedMes.isAA()) {
1029:                                        slist.updateEntry(workZone, curServer,
1030:                                                responseTime);
1031:                                        visitedServers.put(curServer,
1032:                                                new Object()); // $NON-LOCK-1$
1033:                                        correctAnswer = true;
1034:                                        // if (LogConst.DEBUG) {
1035:                                        // ProviderMgr.logger.fine(
1036:                                        // "Return name error to user");
1037:                                        // }
1038:                                        break;
1039:                                    }
1040:                                    // This server is not authoritative server for
1041:                                    // this zone. It should not answer with a
1042:                                    // name error. Probably it is misconfigured.
1043:                                    slist.updateEntry(workZone, curServer,
1044:                                            SList.SERVER_FAILURE);
1045:                                    visitedServers.put(curServer, new Object()); // $NON-LOCK-1$
1046:                                    // if (LogConst.DEBUG) {
1047:                                    // ProviderMgr.logger.fine(
1048:                                    // "Not authoritative answer. " +
1049:                                    // "Skip it.");
1050:                                    // }
1051:                                } else if (rCode == ProviderConstants.NOT_IMPLEMENTED) {
1052:                                    // ProviderMgr.logger.warning("Not implemented. " +
1053:                                    // errMsg);
1054:                                    slist.updateEntry(workZone, curServer,
1055:                                            SList.SERVER_FAILURE);
1056:                                    visitedServers.put(curServer, new Object()); // $NON-LOCK-1$
1057:                                } else if (rCode == ProviderConstants.REFUSED) {
1058:                                    // ProviderMgr.logger.warning("Refused. " +
1059:                                    // errMsg);
1060:                                    slist.updateEntry(workZone, curServer,
1061:                                            SList.SERVER_FAILURE);
1062:                                    visitedServers.put(curServer, new Object()); // $NON-LOCK-1$
1063:                                }
1064:                            } catch (DomainProtocolException e) {
1065:                                // removing this server from SLIST
1066:                                slist.dropServer(workZone, curServer);
1067:                                // ProviderMgr.logger.warning("Unknown error.");
1068:                            } catch (IndexOutOfBoundsException e) {
1069:                                // bad message received
1070:                                slist.dropServer(workZone, curServer);
1071:                                // ProviderMgr.logger.warning("Bad message received: " +
1072:                                // " IndexOutOfBoundsException.");
1073:                            }
1074:                        }
1075:                        queriedServers.add(curServer);
1076:                    }
1077:                    // end of round
1078:
1079:                    if (received & parsed & correctAnswer) {
1080:                        // correct answer received
1081:                        return receivedMes;
1082:                    }
1083:                    curTimeout *= 2;
1084:                }
1085:                // give up - no correct message has been received
1086:                return null;
1087:            }
1088:
1089:            /**
1090:             * Analyzes the answer message and constructs an analysis report.
1091:             * 
1092:             * @param request
1093:             *            the request has been send to the server
1094:             * @param answer
1095:             *            the answer has been received
1096:             * @param workZone
1097:             *            the current resolver's work zone
1098:             * @return analysis report TODO may be optimized
1099:             */
1100:            AnalysisReport analyzeAnswer(Message request, Message answer)
1101:                    throws DomainProtocolException {
1102:                Enumeration<QuestionRecord> questions = request
1103:                        .getQuestionRecords();
1104:                Enumeration<ResourceRecord> answerRRs = answer.getAnswerRRs();
1105:                Enumeration<ResourceRecord> authorityRRs = answer
1106:                        .getAuthorityRRs();
1107:                Enumeration<ResourceRecord> additionalRRs;
1108:                QuestionRecord question;
1109:                Resolver.AnalysisReport report = new AnalysisReport();
1110:
1111:                // Check the ID.
1112:                if (request.getId() != answer.getId()) {
1113:                    // jndi.72=Request and Answer have different ids
1114:                    throw new DomainProtocolException(Messages
1115:                            .getString("jndi.72")); //$NON-NLS-1$
1116:                }
1117:
1118:                // Determine a question.
1119:                if (questions.hasMoreElements()) {
1120:                    question = questions.nextElement();
1121:                } else {
1122:                    // jndi.73=no question record
1123:                    throw new IllegalArgumentException(Messages
1124:                            .getString("jndi.73")); //$NON-NLS-1$
1125:                }
1126:                // If name error occurred - no extra processing needed.
1127:                if (answer.getRCode() == ProviderConstants.NAME_ERROR) {
1128:                    report.nameError = true;
1129:                    return report;
1130:                }
1131:                // check truncation, truncated message should not be cached
1132:                if (answer.isTc()) {
1133:                    report.messageWasTruncated = true;
1134:                }
1135:                // Analyze answer section.
1136:                while (answerRRs.hasMoreElements()) {
1137:                    ResourceRecord curRec = answerRRs.nextElement();
1138:
1139:                    if (question.getQClass() == curRec.getRRClass()
1140:                            || question.getQClass() == ProviderConstants.ANY_QCLASS) {
1141:                        if (question.getQType() == ProviderConstants.ANY_QTYPE
1142:                                && ProviderMgr.namesAreEqual(curRec.getName(),
1143:                                        question.getQName())) {
1144:                            // If we query for ANY record types and the server returns
1145:                            // some record for the SAME domain name we will collect
1146:                            // all of such records and treat
1147:                            // this situation as a complete answer for this query.
1148:                            // We will not perform any more attempts to obtain more
1149:                            // records.
1150:
1151:                            report.records.addElement(curRec);
1152:                            // if (LogConst.DEBUG) {
1153:                            // ProviderMgr.logger.fine("Adding " +
1154:                            // ProviderConstants.rrTypeNames[
1155:                            // curRec.getRRType()]);
1156:                            // }
1157:                            if (curRec.getRRType() == ProviderConstants.CNAME_TYPE) {
1158:                                report.aliasInfoWasReceived = true;
1159:                                report.newName = (String) curRec.getRData();
1160:                                // if (LogConst.DEBUG) {
1161:                                // ProviderMgr.logger.fine("Alias \"" +
1162:                                // report.newName + "\" was received");
1163:                                // }
1164:                            } else {
1165:                                // XXX have we received a complete set of records?
1166:                                report.completeAnswerWasReceived = true;
1167:                            }
1168:                        } else if (question.getQType() == curRec.getRRType()
1169:                                && ProviderMgr.namesAreEqual(question
1170:                                        .getQName(), curRec.getName())) {
1171:                            // This is a situation when we get the record with the
1172:                            // name and type exactly matching to that we have asked for.
1173:                            // We will treat this as a complete answer.
1174:
1175:                            report.records.addElement(curRec);
1176:                            // if (LogConst.DEBUG) {
1177:                            // ProviderMgr.logger.fine("Adding " +
1178:                            // ProviderConstants.rrTypeNames[
1179:                            // curRec.getRRType()]);
1180:                            // }
1181:                            report.completeAnswerWasReceived = true;
1182:                        } else if (curRec.getRRType() == ProviderConstants.CNAME_TYPE
1183:                                && ProviderMgr.namesAreEqual(curRec.getName(),
1184:                                        question.getQName())) {
1185:                            // This is the case of an alias. If we received an alias for
1186:                            // the name we have asked the information for then we need
1187:                            // to change the desired name to this newly received name.
1188:                            // Then we will try to find necessary information for
1189:                            // this new name in the current answer. If we fail then
1190:                            // we will continue our general lookup algorithm with the
1191:                            // new name instead of an old one. We will query servers
1192:                            // from the SLIST with this new name.
1193:
1194:                            // TODO this is not effective
1195:                            Enumeration<ResourceRecord> answerRRs2 = answer
1196:                                    .getAnswerRRs();
1197:                            Enumeration<ResourceRecord> additionalRRs2 = answer
1198:                                    .getAdditionalRRs();
1199:
1200:                            report.aliasInfoWasReceived = true;
1201:                            report.newName = (String) curRec.getRData();
1202:                            report.extraRecords.addElement(curRec);
1203:                            // if (LogConst.DEBUG) {
1204:                            // ProviderMgr.logger.fine("Alias \"" + report.newName +
1205:                            // "\" was received");
1206:                            // }
1207:                            // if we find the one of desired records in the
1208:                            // current answer then we will treat the answer as complete
1209:                            while (answerRRs2.hasMoreElements()) {
1210:
1211:                                // Try to look for info about newly received name
1212:                                // in ANSWER section.
1213:
1214:                                ResourceRecord tmpRec = answerRRs2
1215:                                        .nextElement();
1216:
1217:                                // if (LogConst.DEBUG) {
1218:                                // ProviderMgr.logger.fine(
1219:                                // "Look for an answer in ANSWER section");
1220:                                // }
1221:                                if (tmpRec.getRRType() == question.getQType()
1222:                                        && ProviderMgr.namesAreEqual(tmpRec
1223:                                                .getName(), report.newName)) {
1224:                                    // the answer is founded in ANSWER section
1225:                                    report.records.addElement(tmpRec);
1226:                                    // if (LogConst.DEBUG) {
1227:                                    // ProviderMgr.logger.fine("Adding " +
1228:                                    // ProviderConstants.rrTypeNames[
1229:                                    // tmpRec.getRRType()]);
1230:                                    // }
1231:                                    report.completeAnswerWasReceived = true;
1232:                                }
1233:                            }
1234:                            while (additionalRRs2.hasMoreElements()) {
1235:                                // Try to look for info about newly received name
1236:                                // in ADDITIONAL section.
1237:
1238:                                ResourceRecord tmpRec = additionalRRs2
1239:                                        .nextElement();
1240:
1241:                                // if (LogConst.DEBUG) {
1242:                                // ProviderMgr.logger.fine("Look for an answer in " +
1243:                                // "ADDITIONAL section");
1244:                                // }
1245:                                if (tmpRec.getRRType() == question.getQType()
1246:                                        && ProviderMgr.namesAreEqual(tmpRec
1247:                                                .getName(), report.newName)) {
1248:                                    // the answer is founded in ADDITIONAL section
1249:                                    report.records.addElement(tmpRec);
1250:                                    // if (LogConst.DEBUG) {
1251:                                    // ProviderMgr.logger.fine("Adding " +
1252:                                    // ProviderConstants.rrTypeNames[
1253:                                    // tmpRec.getRRType()]);
1254:                                    // }
1255:                                    report.completeAnswerWasReceived = true;
1256:                                }
1257:                            }
1258:                            // if (report.completeAnswerWasReceived) {
1259:                            // if (LogConst.DEBUG) {
1260:                            // ProviderMgr.logger.fine("Complete answer received");
1261:                            // }
1262:                            // }
1263:                        } else {
1264:                            // We have received some extra records. Let's save it for
1265:                            // future use.
1266:
1267:                            // we will treat authoritative answer as a complete answer
1268:                            // and in no case will perform further actions
1269:                            if (answer.isAA()) {
1270:                                report.completeAnswerWasReceived = true;
1271:                            }
1272:                            report.extraRecords.addElement(curRec);
1273:                            // if (LogConst.DEBUG) {
1274:                            // ProviderMgr.logger.fine("Adding additional record " +
1275:                            // ProviderConstants.rrTypeNames[
1276:                            // curRec.getRRType()]);
1277:                            // }
1278:                        }
1279:                    } else {
1280:                        // The record from another DNS class arrived. Just ignore it.
1281:                        // if (LogConst.DEBUG) {
1282:                        // ProviderMgr.logger.fine("Ignore records from DNS class " +
1283:                        // curRec.getRRClass());
1284:                        // }
1285:                    }
1286:                }
1287:
1288:                // analyze authority section
1289:                // 1. Store all info from authority NS records; try to locate NS IPs
1290:                // from additional records in case if it is not present in SLIST;
1291:                // start new background lookup process if not found in additional
1292:                // section
1293:                // TODO current implementation isn't effective
1294:                while (authorityRRs.hasMoreElements()) {
1295:                    ResourceRecord curRec = authorityRRs.nextElement();
1296:                    SList slist = SList.getInstance();
1297:
1298:                    // save record for future use
1299:                    report.extraRecords.addElement(curRec);
1300:                    // analyze
1301:                    if (curRec.getRRType() == ProviderConstants.NS_TYPE) {
1302:                        String serverName = (String) curRec.getRData();
1303:                        SList.Server server2 = new SList.Server(serverName,
1304:                                null, ProviderConstants.DEFAULT_DNS_PORT);
1305:                        SList.Server server = slist.getServerByServer(curRec
1306:                                .getName(), server2);
1307:
1308:                        report.delegationArrived = true;
1309:                        if (server == null) {
1310:                            // not found in SLIST
1311:                            slist.updateEntry(curRec.getName(), server2,
1312:                                    SList.UNKNOWN);
1313:                            report.delegationZones.addElement(curRec.getName());
1314:                            server = server2;
1315:                        }
1316:                        if (server != null && server.getIP() == null) {
1317:                            // try to search additional records to obtain server's IP
1318:                            additionalRRs = answer.getAdditionalRRs();
1319:                            while (additionalRRs.hasMoreElements()) {
1320:                                ResourceRecord addRec = additionalRRs
1321:                                        .nextElement();
1322:
1323:                                if (ProviderMgr.namesAreEqual(addRec.getName(),
1324:                                        serverName)
1325:                                        && addRec.getRRType() == ProviderConstants.A_TYPE) {
1326:                                    server.setIP((String) addRec.getRData());
1327:                                }
1328:                            }
1329:                            if (server.getIP() == null) {
1330:                                // IP was not found in additional section
1331:                                // start resolving process in the background
1332:                                this .startResolvingThread(server.getName(),
1333:                                        curRec.getRRClass());
1334:                            }
1335:                        }
1336:                        // if (LogConst.DEBUG) {
1337:                        // ProviderMgr.logger.fine("Delegation \"" + server +
1338:                        // "\" arrived");
1339:                        // }
1340:                    } // end of NS type analysis
1341:                } // end of authority section analysis
1342:
1343:                // analyze additional section
1344:                additionalRRs = answer.getAdditionalRRs();
1345:                while (additionalRRs.hasMoreElements()) {
1346:                    ResourceRecord addRec = additionalRRs.nextElement();
1347:
1348:                    report.extraRecords.addElement(addRec);
1349:                    // if (LogConst.DEBUG) {
1350:                    // ProviderMgr.logger.fine("Adding additional record " +
1351:                    // ProviderConstants.rrTypeNames[addRec.getRRType()]);
1352:                    // }
1353:                }
1354:
1355:                // Fixing RRSet TTL issue.
1356:                // If TTL fields in RRSet are not all the same then we need to set
1357:                // all TTLs to lowest found value.
1358:                // See RFC 2181 point 5.2
1359:
1360:                // checking report.records and report.extraRecords
1361:                for (int k = 0; k < 2; k++) {
1362:                    Vector<ResourceRecord> records = null;
1363:                    HashSet<String> processed = new HashSet<String>();
1364:
1365:                    switch (k) {
1366:                    case 0:
1367:                        records = report.records;
1368:                        break;
1369:                    case 1:
1370:                        records = report.extraRecords;
1371:                        break;
1372:                    }
1373:                    for (int i = 0; i < records.size(); i++) {
1374:                        ResourceRecord rr = records.elementAt(i);
1375:                        String key = rr.getName()
1376:                                + " " + rr.getRRClass() + " " + //$NON-NLS-1$ //$NON-NLS-2$
1377:                                rr.getRRType();
1378:                        long ttl = rr.getTtl();
1379:                        Vector<ResourceRecord> objToUpdateTTL = new Vector<ResourceRecord>();
1380:
1381:                        if (processed.contains(key)) {
1382:                            continue;
1383:                        }
1384:                        objToUpdateTTL.addElement(rr);
1385:                        // look forward for records with the same NAME CLASS TYPE
1386:                        for (int j = i; j < records.size(); j++) {
1387:                            ResourceRecord rr2 = records.elementAt(j);
1388:                            String key2 = rr2.getName()
1389:                                    + " " + rr2.getRRClass() + " " + //$NON-NLS-1$ //$NON-NLS-2$
1390:                                    rr2.getRRType();
1391:                            long ttl2 = rr2.getTtl();
1392:
1393:                            if (processed.contains(key2)) {
1394:                                continue;
1395:                            }
1396:                            if (key.equals(key2)) {
1397:                                if (ttl > ttl2) {
1398:                                    ttl = ttl2;
1399:                                }
1400:                                objToUpdateTTL.addElement(rr2);
1401:                            }
1402:                        }
1403:                        // update TTL if necessary
1404:                        for (int j = 0; j < objToUpdateTTL.size(); j++) {
1405:                            ResourceRecord rr2 = objToUpdateTTL.elementAt(j);
1406:
1407:                            if (rr2.getTtl() != ttl) {
1408:                                rr2.setTtl(ttl);
1409:                            }
1410:                        }
1411:                        // don't process such NAME CLASS TYPE combination any more
1412:                        processed.add(key);
1413:                    }
1414:                } // fixing RRSet TTL issue
1415:
1416:                return report;
1417:            }
1418:
1419:            /**
1420:             * Creates a new <code>Message</code> object and fills some of it's
1421:             * standard fields.
1422:             * 
1423:             * @return created <code>Message</code> object
1424:             */
1425:            static Message createMessageForSending(String desiredName,
1426:                    int recType, int recClass) throws DomainProtocolException {
1427:                Message mes = new Message();
1428:                QuestionRecord qr = new QuestionRecord();
1429:
1430:                mes.setId(rndGen.nextInt() & 0xffff);
1431:                mes.setQR(ProviderConstants.QR_QUERY);
1432:                mes.setOpCode(ProviderConstants.QUERY);
1433:                mes.setRD(true);
1434:                mes.setQDCount(1);
1435:                qr.setQName(desiredName);
1436:                qr.setQType(recType);
1437:                qr.setQClass(recClass);
1438:                mes.addQuestionRecord(qr);
1439:                return mes;
1440:            }
1441:
1442:            /**
1443:             * Starts new resolver thread that will be searching for IP of the given
1444:             * hostname.
1445:             * 
1446:             * @param hostname
1447:             *            hostname to resolve
1448:             * @param dnsClass
1449:             *            DNS class of host
1450:             */
1451:            void startResolvingThread(String hostname, int dnsClass) {
1452:                Thread newThread;
1453:                Resolver.ThreadListEntry newEntry;
1454:                int classes[] = new int[1];
1455:
1456:                synchronized (threadListSemaphore) {
1457:                    // check that no currently running thread looks for this hostname
1458:                    for (int i = 0; i < resolverThreads.size(); i++) {
1459:                        Resolver.ThreadListEntry entry = resolverThreads.get(i);
1460:                        if (ProviderMgr.namesAreEqual(hostname,
1461:                                entry.serverNameToResolve)
1462:                                && entry.dnsClass == dnsClass) {
1463:                            // this hostname is already under investigation
1464:                            // exiting
1465:                            return;
1466:                        }
1467:                    }
1468:                    // check if the hostname is already scheduled for resolving
1469:                    for (int i = 0; i < hostnamesToResolve.size(); i++) {
1470:                        Resolver.ThreadListEntry entry = hostnamesToResolve
1471:                                .get(i);
1472:                        if (ProviderMgr.namesAreEqual(hostname,
1473:                                entry.serverNameToResolve)
1474:                                && entry.dnsClass == dnsClass) {
1475:                            // this hostname is already scheduled for resolving
1476:                            // exiting
1477:                            return;
1478:                        }
1479:                    }
1480:                    // check that the maximum number of threads is not exceeded
1481:                    if (resolverThreads.size() >= threadNumberLimit) {
1482:                        // maximum possible number of threads is reached already
1483:                        return;
1484:                    }
1485:                    classes[0] = dnsClass;
1486:                    newEntry = new Resolver.ThreadListEntry();
1487:                    newEntry.serverNameToResolve = hostname;
1488:                    newEntry.dnsClass = dnsClass;
1489:                    hostnamesToResolve.add(newEntry);
1490:                    // starting new thread that should make further updates by itself
1491:                    newThread = new Thread(this );
1492:                    // if (LogConst.DEBUG) {
1493:                    // ProviderMgr.logger.fine("Starting new resolver thread," +
1494:                    // " target hostname: " + hostname);
1495:                    // }
1496:                    newThread.start();
1497:                }
1498:            }
1499:
1500:            /**
1501:             * Start background search of the address of next unresolved server hostname
1502:             */
1503:            public void run() {
1504:                SList slist = SList.getInstance();
1505:                Enumeration<ResourceRecord> foundRecords;
1506:                Resolver.ThreadListEntry entryToProcess;
1507:                int[] classes = new int[1];
1508:
1509:                // update lists
1510:                synchronized (threadListSemaphore) {
1511:                    if (hostnamesToResolve.size() > 0) {
1512:                        entryToProcess = hostnamesToResolve.get(0);
1513:                        hostnamesToResolve.remove(0);
1514:                        entryToProcess.thread = Thread.currentThread();
1515:                        resolverThreads.add(entryToProcess);
1516:                    } else {
1517:                        // ProviderMgr.logger.warning(
1518:                        // "Resolver thread: no host name to resolve");
1519:                        return;
1520:                    }
1521:                }
1522:                // lookup
1523:                try {
1524:                    classes[0] = entryToProcess.dnsClass;
1525:                    foundRecords = lookup(entryToProcess.serverNameToResolve,
1526:                            new int[] { ProviderConstants.A_TYPE }, classes);
1527:                    while (foundRecords != null
1528:                            && foundRecords.hasMoreElements()) {
1529:                        // we will take all A records and store all of them in SLIST
1530:                        ResourceRecord rr = foundRecords.nextElement();
1531:
1532:                        if (rr.getRRType() == ProviderConstants.A_TYPE) {
1533:                            slist.setServerIP(
1534:                                    entryToProcess.serverNameToResolve,
1535:                                    (String) rr.getRData());
1536:                        }
1537:                    }
1538:                } catch (NamingException e) {
1539:                    // just ignore it
1540:                }
1541:                // update resolver threads list, remove info about current thread
1542:                synchronized (threadListSemaphore) {
1543:                    for (int i = 0; i < resolverThreads.size(); i++) {
1544:                        Resolver.ThreadListEntry entry = resolverThreads.get(i);
1545:
1546:                        if (ProviderMgr.namesAreEqual(
1547:                                entryToProcess.serverNameToResolve,
1548:                                entry.serverNameToResolve)
1549:                                && entryToProcess.dnsClass == entry.dnsClass) {
1550:                            resolverThreads.remove(i);
1551:                            break;
1552:                        }
1553:                    }
1554:                }
1555:                // exiting
1556:            }
1557:
1558:            /**
1559:             * Analysis report.
1560:             * 
1561:             * @see Resolver#analyzeAnswer(Message, Message)
1562:             */
1563:            static class AnalysisReport {
1564:
1565:                boolean completeAnswerWasReceived = false;
1566:
1567:                boolean nameError = false;
1568:
1569:                boolean delegationArrived = false;
1570:
1571:                boolean aliasInfoWasReceived = false;
1572:
1573:                boolean messageWasTruncated = false;
1574:
1575:                Vector<ResourceRecord> records;
1576:
1577:                Vector<String> delegationZones;
1578:
1579:                String newName = null;
1580:
1581:                Vector<ResourceRecord> extraRecords;
1582:
1583:                AnalysisReport() {
1584:                    records = new Vector<ResourceRecord>();
1585:                    delegationZones = new Vector<String>();
1586:                    extraRecords = new Vector<ResourceRecord>();
1587:                }
1588:
1589:            }
1590:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.