jdk/src/share/classes/com/sun/jndi/dns/DnsClient.java
author ohair
Tue, 28 Dec 2010 15:53:50 -0800
changeset 7668 d4a77089c587
parent 5627 e636ac7a63a4
child 10324 e28265130e4f
permissions -rw-r--r--
6962318: Update copyright year Reviewed-by: xdono
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
     1
/*
7668
d4a77089c587 6962318: Update copyright year
ohair
parents: 5627
diff changeset
     2
 * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
     3
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
90ce3da70b43 Initial load
duke
parents:
diff changeset
     4
 *
90ce3da70b43 Initial load
duke
parents:
diff changeset
     5
 * This code is free software; you can redistribute it and/or modify it
90ce3da70b43 Initial load
duke
parents:
diff changeset
     6
 * under the terms of the GNU General Public License version 2 only, as
5506
202f599c92aa 6943119: Rebrand source copyright notices
ohair
parents: 2
diff changeset
     7
 * published by the Free Software Foundation.  Oracle designates this
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
     8
 * particular file as subject to the "Classpath" exception as provided
5506
202f599c92aa 6943119: Rebrand source copyright notices
ohair
parents: 2
diff changeset
     9
 * by Oracle in the LICENSE file that accompanied this code.
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
    10
 *
90ce3da70b43 Initial load
duke
parents:
diff changeset
    11
 * This code is distributed in the hope that it will be useful, but WITHOUT
90ce3da70b43 Initial load
duke
parents:
diff changeset
    12
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
90ce3da70b43 Initial load
duke
parents:
diff changeset
    13
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
90ce3da70b43 Initial load
duke
parents:
diff changeset
    14
 * version 2 for more details (a copy is included in the LICENSE file that
90ce3da70b43 Initial load
duke
parents:
diff changeset
    15
 * accompanied this code).
90ce3da70b43 Initial load
duke
parents:
diff changeset
    16
 *
90ce3da70b43 Initial load
duke
parents:
diff changeset
    17
 * You should have received a copy of the GNU General Public License version
90ce3da70b43 Initial load
duke
parents:
diff changeset
    18
 * 2 along with this work; if not, write to the Free Software Foundation,
90ce3da70b43 Initial load
duke
parents:
diff changeset
    19
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
90ce3da70b43 Initial load
duke
parents:
diff changeset
    20
 *
5506
202f599c92aa 6943119: Rebrand source copyright notices
ohair
parents: 2
diff changeset
    21
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
202f599c92aa 6943119: Rebrand source copyright notices
ohair
parents: 2
diff changeset
    22
 * or visit www.oracle.com if you need additional information or have any
202f599c92aa 6943119: Rebrand source copyright notices
ohair
parents: 2
diff changeset
    23
 * questions.
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
    24
 */
90ce3da70b43 Initial load
duke
parents:
diff changeset
    25
90ce3da70b43 Initial load
duke
parents:
diff changeset
    26
package com.sun.jndi.dns;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    27
90ce3da70b43 Initial load
duke
parents:
diff changeset
    28
import java.io.IOException;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    29
import java.net.DatagramSocket;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    30
import java.net.DatagramPacket;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    31
import java.net.InetAddress;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    32
import java.net.Socket;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    33
import javax.naming.*;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    34
90ce3da70b43 Initial load
duke
parents:
diff changeset
    35
import java.util.Collections;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    36
import java.util.Map;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    37
import java.util.HashMap;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    38
import java.util.Set;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    39
import java.util.HashSet;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    40
90ce3da70b43 Initial load
duke
parents:
diff changeset
    41
// Some of this code began life as part of sun.javaos.net.DnsClient
90ce3da70b43 Initial load
duke
parents:
diff changeset
    42
// originally by sritchie@eng 1/96.  It was first hacked up for JNDI
90ce3da70b43 Initial load
duke
parents:
diff changeset
    43
// use by caveh@eng 6/97.
90ce3da70b43 Initial load
duke
parents:
diff changeset
    44
90ce3da70b43 Initial load
duke
parents:
diff changeset
    45
90ce3da70b43 Initial load
duke
parents:
diff changeset
    46
/**
90ce3da70b43 Initial load
duke
parents:
diff changeset
    47
 * The DnsClient class performs DNS client operations in support of DnsContext.
90ce3da70b43 Initial load
duke
parents:
diff changeset
    48
 *
90ce3da70b43 Initial load
duke
parents:
diff changeset
    49
 */
90ce3da70b43 Initial load
duke
parents:
diff changeset
    50
90ce3da70b43 Initial load
duke
parents:
diff changeset
    51
public class DnsClient {
90ce3da70b43 Initial load
duke
parents:
diff changeset
    52
90ce3da70b43 Initial load
duke
parents:
diff changeset
    53
    // DNS packet header field offsets
90ce3da70b43 Initial load
duke
parents:
diff changeset
    54
    private static final int IDENT_OFFSET = 0;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    55
    private static final int FLAGS_OFFSET = 2;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    56
    private static final int NUMQ_OFFSET  = 4;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    57
    private static final int NUMANS_OFFSET = 6;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    58
    private static final int NUMAUTH_OFFSET = 8;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    59
    private static final int NUMADD_OFFSET = 10;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    60
    private static final int DNS_HDR_SIZE = 12;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    61
90ce3da70b43 Initial load
duke
parents:
diff changeset
    62
    // DNS response codes
90ce3da70b43 Initial load
duke
parents:
diff changeset
    63
    private static final int NO_ERROR       = 0;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    64
    private static final int FORMAT_ERROR   = 1;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    65
    private static final int SERVER_FAILURE = 2;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    66
    private static final int NAME_ERROR     = 3;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    67
    private static final int NOT_IMPL       = 4;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    68
    private static final int REFUSED        = 5;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    69
90ce3da70b43 Initial load
duke
parents:
diff changeset
    70
    private static final String[] rcodeDescription = {
90ce3da70b43 Initial load
duke
parents:
diff changeset
    71
        "No error",
90ce3da70b43 Initial load
duke
parents:
diff changeset
    72
        "DNS format error",
90ce3da70b43 Initial load
duke
parents:
diff changeset
    73
        "DNS server failure",
90ce3da70b43 Initial load
duke
parents:
diff changeset
    74
        "DNS name not found",
90ce3da70b43 Initial load
duke
parents:
diff changeset
    75
        "DNS operation not supported",
90ce3da70b43 Initial load
duke
parents:
diff changeset
    76
        "DNS service refused"
90ce3da70b43 Initial load
duke
parents:
diff changeset
    77
    };
90ce3da70b43 Initial load
duke
parents:
diff changeset
    78
90ce3da70b43 Initial load
duke
parents:
diff changeset
    79
    private static final int DEFAULT_PORT = 53;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    80
    private InetAddress[] servers;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    81
    private int[] serverPorts;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    82
    private int timeout;                // initial timeout on UDP queries in ms
90ce3da70b43 Initial load
duke
parents:
diff changeset
    83
    private int retries;                // number of UDP retries
90ce3da70b43 Initial load
duke
parents:
diff changeset
    84
90ce3da70b43 Initial load
duke
parents:
diff changeset
    85
    private DatagramSocket udpSocket;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    86
90ce3da70b43 Initial load
duke
parents:
diff changeset
    87
    // Requests sent
90ce3da70b43 Initial load
duke
parents:
diff changeset
    88
    private Set<Integer> reqs;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    89
90ce3da70b43 Initial load
duke
parents:
diff changeset
    90
    // Responses received
90ce3da70b43 Initial load
duke
parents:
diff changeset
    91
    private Map<Integer, byte[]> resps;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    92
90ce3da70b43 Initial load
duke
parents:
diff changeset
    93
    //-------------------------------------------------------------------------
90ce3da70b43 Initial load
duke
parents:
diff changeset
    94
90ce3da70b43 Initial load
duke
parents:
diff changeset
    95
    /*
90ce3da70b43 Initial load
duke
parents:
diff changeset
    96
     * Each server is of the form "server[:port]".  IPv6 literal host names
90ce3da70b43 Initial load
duke
parents:
diff changeset
    97
     * include delimiting brackets.
90ce3da70b43 Initial load
duke
parents:
diff changeset
    98
     * "timeout" is the initial timeout interval (in ms) for UDP queries,
90ce3da70b43 Initial load
duke
parents:
diff changeset
    99
     * and "retries" gives the number of retries per server.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   100
     */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   101
    public DnsClient(String[] servers, int timeout, int retries)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   102
            throws NamingException {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   103
        this.timeout = timeout;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   104
        this.retries = retries;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   105
        try {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   106
            udpSocket = new DatagramSocket();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   107
        } catch (java.net.SocketException e) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   108
            NamingException ne = new ConfigurationException();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   109
            ne.setRootCause(e);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   110
            throw ne;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   111
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   112
90ce3da70b43 Initial load
duke
parents:
diff changeset
   113
        this.servers = new InetAddress[servers.length];
90ce3da70b43 Initial load
duke
parents:
diff changeset
   114
        serverPorts = new int[servers.length];
90ce3da70b43 Initial load
duke
parents:
diff changeset
   115
90ce3da70b43 Initial load
duke
parents:
diff changeset
   116
        for (int i = 0; i < servers.length; i++) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   117
90ce3da70b43 Initial load
duke
parents:
diff changeset
   118
            // Is optional port given?
90ce3da70b43 Initial load
duke
parents:
diff changeset
   119
            int colon = servers[i].indexOf(':',
90ce3da70b43 Initial load
duke
parents:
diff changeset
   120
                                           servers[i].indexOf(']') + 1);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   121
90ce3da70b43 Initial load
duke
parents:
diff changeset
   122
            serverPorts[i] = (colon < 0)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   123
                ? DEFAULT_PORT
90ce3da70b43 Initial load
duke
parents:
diff changeset
   124
                : Integer.parseInt(servers[i].substring(colon + 1));
90ce3da70b43 Initial load
duke
parents:
diff changeset
   125
            String server = (colon < 0)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   126
                ? servers[i]
90ce3da70b43 Initial load
duke
parents:
diff changeset
   127
                : servers[i].substring(0, colon);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   128
            try {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   129
                this.servers[i] = InetAddress.getByName(server);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   130
            } catch (java.net.UnknownHostException e) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   131
                NamingException ne = new ConfigurationException(
90ce3da70b43 Initial load
duke
parents:
diff changeset
   132
                        "Unknown DNS server: " + server);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   133
                ne.setRootCause(e);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   134
                throw ne;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   135
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   136
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   137
        reqs = Collections.synchronizedSet(new HashSet<Integer>());
90ce3da70b43 Initial load
duke
parents:
diff changeset
   138
        resps = Collections.synchronizedMap(new HashMap<Integer, byte[]>());
90ce3da70b43 Initial load
duke
parents:
diff changeset
   139
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   140
90ce3da70b43 Initial load
duke
parents:
diff changeset
   141
    protected void finalize() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   142
        close();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   143
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   144
90ce3da70b43 Initial load
duke
parents:
diff changeset
   145
    // A lock to access the request and response queues in tandem.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   146
    private Object queuesLock = new Object();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   147
90ce3da70b43 Initial load
duke
parents:
diff changeset
   148
    public void close() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   149
        udpSocket.close();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   150
        synchronized (queuesLock) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   151
            reqs.clear();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   152
            resps.clear();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   153
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   154
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   155
90ce3da70b43 Initial load
duke
parents:
diff changeset
   156
90ce3da70b43 Initial load
duke
parents:
diff changeset
   157
    private int ident = 0;              // used to set the msg ID field
90ce3da70b43 Initial load
duke
parents:
diff changeset
   158
    private Object identLock = new Object();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   159
90ce3da70b43 Initial load
duke
parents:
diff changeset
   160
    /*
90ce3da70b43 Initial load
duke
parents:
diff changeset
   161
     * If recursion is true, recursion is requested on the query.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   162
     * If auth is true, only authoritative responses are accepted; other
90ce3da70b43 Initial load
duke
parents:
diff changeset
   163
     * responses throw NameNotFoundException.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   164
     */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   165
    ResourceRecords query(DnsName fqdn, int qclass, int qtype,
90ce3da70b43 Initial load
duke
parents:
diff changeset
   166
                          boolean recursion, boolean auth)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   167
            throws NamingException {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   168
90ce3da70b43 Initial load
duke
parents:
diff changeset
   169
        int xid;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   170
        synchronized (identLock) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   171
            ident = 0xFFFF & (ident + 1);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   172
            xid = ident;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   173
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   174
90ce3da70b43 Initial load
duke
parents:
diff changeset
   175
        // enqueue the outstanding request
90ce3da70b43 Initial load
duke
parents:
diff changeset
   176
        reqs.add(xid);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   177
90ce3da70b43 Initial load
duke
parents:
diff changeset
   178
        Packet pkt = makeQueryPacket(fqdn, xid, qclass, qtype, recursion);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   179
90ce3da70b43 Initial load
duke
parents:
diff changeset
   180
        Exception caughtException = null;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   181
        boolean[] doNotRetry = new boolean[servers.length];
90ce3da70b43 Initial load
duke
parents:
diff changeset
   182
90ce3da70b43 Initial load
duke
parents:
diff changeset
   183
        //
90ce3da70b43 Initial load
duke
parents:
diff changeset
   184
        // The UDP retry strategy is to try the 1st server, and then
90ce3da70b43 Initial load
duke
parents:
diff changeset
   185
        // each server in order. If no answer, double the timeout
90ce3da70b43 Initial load
duke
parents:
diff changeset
   186
        // and try each server again.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   187
        //
90ce3da70b43 Initial load
duke
parents:
diff changeset
   188
        for (int retry = 0; retry < retries; retry++) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   189
90ce3da70b43 Initial load
duke
parents:
diff changeset
   190
            // Try each name server.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   191
            for (int i = 0; i < servers.length; i++) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   192
                if (doNotRetry[i]) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   193
                    continue;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   194
                }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   195
90ce3da70b43 Initial load
duke
parents:
diff changeset
   196
                // send the request packet and wait for a response.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   197
                try {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   198
                    if (debug) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   199
                        dprint("SEND ID (" + (retry + 1) + "): " + xid);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   200
                    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   201
90ce3da70b43 Initial load
duke
parents:
diff changeset
   202
                    byte[] msg = null;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   203
                    msg = doUdpQuery(pkt, servers[i], serverPorts[i],
90ce3da70b43 Initial load
duke
parents:
diff changeset
   204
                                        retry, xid);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   205
                    //
90ce3da70b43 Initial load
duke
parents:
diff changeset
   206
                    // If the matching response is not got within the
90ce3da70b43 Initial load
duke
parents:
diff changeset
   207
                    // given timeout, check if the response was enqueued
90ce3da70b43 Initial load
duke
parents:
diff changeset
   208
                    // by some other thread, if not proceed with the next
90ce3da70b43 Initial load
duke
parents:
diff changeset
   209
                    // server or retry.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   210
                    //
90ce3da70b43 Initial load
duke
parents:
diff changeset
   211
                    if (msg == null) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   212
                        if (resps.size() > 0) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   213
                            msg = lookupResponse(xid);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   214
                        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   215
                        if (msg == null) { // try next server or retry
90ce3da70b43 Initial load
duke
parents:
diff changeset
   216
                            continue;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   217
                        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   218
                    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   219
                    Header hdr = new Header(msg, msg.length);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   220
90ce3da70b43 Initial load
duke
parents:
diff changeset
   221
                    if (auth && !hdr.authoritative) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   222
                        caughtException = new NameNotFoundException(
90ce3da70b43 Initial load
duke
parents:
diff changeset
   223
                                "DNS response not authoritative");
90ce3da70b43 Initial load
duke
parents:
diff changeset
   224
                        doNotRetry[i] = true;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   225
                        continue;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   226
                    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   227
                    if (hdr.truncated) {    // message is truncated -- try TCP
90ce3da70b43 Initial load
duke
parents:
diff changeset
   228
90ce3da70b43 Initial load
duke
parents:
diff changeset
   229
                        // Try each server, starting with the one that just
90ce3da70b43 Initial load
duke
parents:
diff changeset
   230
                        // provided the truncated message.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   231
                        for (int j = 0; j < servers.length; j++) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   232
                            int ij = (i + j) % servers.length;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   233
                            if (doNotRetry[ij]) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   234
                                continue;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   235
                            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   236
                            try {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   237
                                Tcp tcp =
90ce3da70b43 Initial load
duke
parents:
diff changeset
   238
                                    new Tcp(servers[ij], serverPorts[ij]);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   239
                                byte[] msg2;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   240
                                try {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   241
                                    msg2 = doTcpQuery(tcp, pkt);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   242
                                } finally {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   243
                                    tcp.close();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   244
                                }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   245
                                Header hdr2 = new Header(msg2, msg2.length);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   246
                                if (hdr2.query) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   247
                                    throw new CommunicationException(
90ce3da70b43 Initial load
duke
parents:
diff changeset
   248
                                        "DNS error: expecting response");
90ce3da70b43 Initial load
duke
parents:
diff changeset
   249
                                }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   250
                                checkResponseCode(hdr2);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   251
90ce3da70b43 Initial load
duke
parents:
diff changeset
   252
                                if (!auth || hdr2.authoritative) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   253
                                    // Got a valid response
90ce3da70b43 Initial load
duke
parents:
diff changeset
   254
                                    hdr = hdr2;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   255
                                    msg = msg2;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   256
                                    break;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   257
                                } else {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   258
                                    doNotRetry[ij] = true;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   259
                                }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   260
                            } catch (Exception e) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   261
                                // Try next server, or use UDP response
90ce3da70b43 Initial load
duke
parents:
diff changeset
   262
                            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   263
                        } // servers
90ce3da70b43 Initial load
duke
parents:
diff changeset
   264
                    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   265
                    return new ResourceRecords(msg, msg.length, hdr, false);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   266
90ce3da70b43 Initial load
duke
parents:
diff changeset
   267
                } catch (IOException e) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   268
                    if (debug) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   269
                        dprint("Caught IOException:" + e);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   270
                    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   271
                    if (caughtException == null) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   272
                        caughtException = e;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   273
                    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   274
                    // Use reflection to allow pre-1.4 compilation.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   275
                    // This won't be needed much longer.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   276
                    if (e.getClass().getName().equals(
90ce3da70b43 Initial load
duke
parents:
diff changeset
   277
                            "java.net.PortUnreachableException")) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   278
                        doNotRetry[i] = true;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   279
                    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   280
                } catch (NameNotFoundException e) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   281
                    throw e;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   282
                } catch (CommunicationException e) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   283
                    if (caughtException == null) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   284
                        caughtException = e;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   285
                    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   286
                } catch (NamingException e) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   287
                    if (caughtException == null) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   288
                        caughtException = e;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   289
                    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   290
                    doNotRetry[i] = true;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   291
                }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   292
            } // servers
90ce3da70b43 Initial load
duke
parents:
diff changeset
   293
        } // retries
90ce3da70b43 Initial load
duke
parents:
diff changeset
   294
90ce3da70b43 Initial load
duke
parents:
diff changeset
   295
        reqs.remove(xid);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   296
        if (caughtException instanceof NamingException) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   297
            throw (NamingException) caughtException;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   298
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   299
        // A network timeout or other error occurred.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   300
        NamingException ne = new CommunicationException("DNS error");
90ce3da70b43 Initial load
duke
parents:
diff changeset
   301
        ne.setRootCause(caughtException);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   302
        throw ne;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   303
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   304
90ce3da70b43 Initial load
duke
parents:
diff changeset
   305
    ResourceRecords queryZone(DnsName zone, int qclass, boolean recursion)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   306
            throws NamingException {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   307
90ce3da70b43 Initial load
duke
parents:
diff changeset
   308
        int xid;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   309
        synchronized (identLock) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   310
            ident = 0xFFFF & (ident + 1);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   311
            xid = ident;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   312
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   313
        Packet pkt = makeQueryPacket(zone, xid, qclass,
90ce3da70b43 Initial load
duke
parents:
diff changeset
   314
                                     ResourceRecord.QTYPE_AXFR, recursion);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   315
        Exception caughtException = null;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   316
90ce3da70b43 Initial load
duke
parents:
diff changeset
   317
        // Try each name server.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   318
        for (int i = 0; i < servers.length; i++) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   319
            try {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   320
                Tcp tcp = new Tcp(servers[i], serverPorts[i]);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   321
                byte[] msg;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   322
                try {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   323
                    msg = doTcpQuery(tcp, pkt);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   324
                    Header hdr = new Header(msg, msg.length);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   325
                    // Check only rcode as per
90ce3da70b43 Initial load
duke
parents:
diff changeset
   326
                    // draft-ietf-dnsext-axfr-clarify-04
90ce3da70b43 Initial load
duke
parents:
diff changeset
   327
                    checkResponseCode(hdr);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   328
                    ResourceRecords rrs =
90ce3da70b43 Initial load
duke
parents:
diff changeset
   329
                        new ResourceRecords(msg, msg.length, hdr, true);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   330
                    if (rrs.getFirstAnsType() != ResourceRecord.TYPE_SOA) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   331
                        throw new CommunicationException(
90ce3da70b43 Initial load
duke
parents:
diff changeset
   332
                                "DNS error: zone xfer doesn't begin with SOA");
90ce3da70b43 Initial load
duke
parents:
diff changeset
   333
                    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   334
90ce3da70b43 Initial load
duke
parents:
diff changeset
   335
                    if (rrs.answer.size() == 1 ||
90ce3da70b43 Initial load
duke
parents:
diff changeset
   336
                            rrs.getLastAnsType() != ResourceRecord.TYPE_SOA) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   337
                        // The response is split into multiple DNS messages.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   338
                        do {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   339
                            msg = continueTcpQuery(tcp);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   340
                            if (msg == null) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   341
                                throw new CommunicationException(
90ce3da70b43 Initial load
duke
parents:
diff changeset
   342
                                        "DNS error: incomplete zone transfer");
90ce3da70b43 Initial load
duke
parents:
diff changeset
   343
                            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   344
                            hdr = new Header(msg, msg.length);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   345
                            checkResponseCode(hdr);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   346
                            rrs.add(msg, msg.length, hdr);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   347
                        } while (rrs.getLastAnsType() !=
90ce3da70b43 Initial load
duke
parents:
diff changeset
   348
                                 ResourceRecord.TYPE_SOA);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   349
                    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   350
90ce3da70b43 Initial load
duke
parents:
diff changeset
   351
                    // Delete the duplicate SOA record.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   352
                    rrs.answer.removeElementAt(rrs.answer.size() - 1);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   353
                    return rrs;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   354
90ce3da70b43 Initial load
duke
parents:
diff changeset
   355
                } finally {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   356
                    tcp.close();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   357
                }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   358
90ce3da70b43 Initial load
duke
parents:
diff changeset
   359
            } catch (IOException e) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   360
                caughtException = e;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   361
            } catch (NameNotFoundException e) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   362
                throw e;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   363
            } catch (NamingException e) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   364
                caughtException = e;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   365
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   366
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   367
        if (caughtException instanceof NamingException) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   368
            throw (NamingException) caughtException;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   369
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   370
        NamingException ne = new CommunicationException(
90ce3da70b43 Initial load
duke
parents:
diff changeset
   371
                "DNS error during zone transfer");
90ce3da70b43 Initial load
duke
parents:
diff changeset
   372
        ne.setRootCause(caughtException);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   373
        throw ne;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   374
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   375
90ce3da70b43 Initial load
duke
parents:
diff changeset
   376
90ce3da70b43 Initial load
duke
parents:
diff changeset
   377
    /**
90ce3da70b43 Initial load
duke
parents:
diff changeset
   378
     * Tries to retreive an UDP packet matching the given xid
90ce3da70b43 Initial load
duke
parents:
diff changeset
   379
     * received within the timeout.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   380
     * If a packet with different xid is received, the received packet
90ce3da70b43 Initial load
duke
parents:
diff changeset
   381
     * is enqueued with the corresponding xid in 'resps'.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   382
     */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   383
    private byte[] doUdpQuery(Packet pkt, InetAddress server,
90ce3da70b43 Initial load
duke
parents:
diff changeset
   384
                                     int port, int retry, int xid)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   385
            throws IOException, NamingException {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   386
90ce3da70b43 Initial load
duke
parents:
diff changeset
   387
        int minTimeout = 50; // msec after which there are no retries.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   388
90ce3da70b43 Initial load
duke
parents:
diff changeset
   389
        synchronized (udpSocket) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   390
            DatagramPacket opkt = new DatagramPacket(
90ce3da70b43 Initial load
duke
parents:
diff changeset
   391
                    pkt.getData(), pkt.length(), server, port);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   392
            DatagramPacket ipkt = new DatagramPacket(new byte[8000], 8000);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   393
            udpSocket.connect(server, port);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   394
            int pktTimeout = (timeout * (1 << retry));
90ce3da70b43 Initial load
duke
parents:
diff changeset
   395
            try {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   396
                udpSocket.send(opkt);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   397
90ce3da70b43 Initial load
duke
parents:
diff changeset
   398
                // timeout remaining after successive 'receive()'
90ce3da70b43 Initial load
duke
parents:
diff changeset
   399
                int timeoutLeft = pktTimeout;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   400
                int cnt = 0;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   401
                do {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   402
                    if (debug) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   403
                       cnt++;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   404
                        dprint("Trying RECEIVE(" +
90ce3da70b43 Initial load
duke
parents:
diff changeset
   405
                                cnt + ") retry(" + (retry + 1) +
90ce3da70b43 Initial load
duke
parents:
diff changeset
   406
                                ") for:" + xid  + "    sock-timeout:" +
90ce3da70b43 Initial load
duke
parents:
diff changeset
   407
                                timeoutLeft + " ms.");
90ce3da70b43 Initial load
duke
parents:
diff changeset
   408
                    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   409
                    udpSocket.setSoTimeout(timeoutLeft);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   410
                    long start = System.currentTimeMillis();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   411
                    udpSocket.receive(ipkt);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   412
                    long end = System.currentTimeMillis();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   413
90ce3da70b43 Initial load
duke
parents:
diff changeset
   414
                    byte[] data = new byte[ipkt.getLength()];
90ce3da70b43 Initial load
duke
parents:
diff changeset
   415
                    data = ipkt.getData();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   416
                    if (isMatchResponse(data, xid)) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   417
                        return data;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   418
                    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   419
                    timeoutLeft = pktTimeout - ((int) (end - start));
90ce3da70b43 Initial load
duke
parents:
diff changeset
   420
                } while (timeoutLeft > minTimeout);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   421
90ce3da70b43 Initial load
duke
parents:
diff changeset
   422
            } finally {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   423
                udpSocket.disconnect();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   424
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   425
            return null; // no matching packet received within the timeout
90ce3da70b43 Initial load
duke
parents:
diff changeset
   426
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   427
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   428
90ce3da70b43 Initial load
duke
parents:
diff changeset
   429
    /*
90ce3da70b43 Initial load
duke
parents:
diff changeset
   430
     * Sends a TCP query, and returns the first DNS message in the response.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   431
     */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   432
    private byte[] doTcpQuery(Tcp tcp, Packet pkt) throws IOException {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   433
90ce3da70b43 Initial load
duke
parents:
diff changeset
   434
        int len = pkt.length();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   435
        // Send 2-byte message length, then send message.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   436
        tcp.out.write(len >> 8);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   437
        tcp.out.write(len);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   438
        tcp.out.write(pkt.getData(), 0, len);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   439
        tcp.out.flush();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   440
90ce3da70b43 Initial load
duke
parents:
diff changeset
   441
        byte[] msg = continueTcpQuery(tcp);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   442
        if (msg == null) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   443
            throw new IOException("DNS error: no response");
90ce3da70b43 Initial load
duke
parents:
diff changeset
   444
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   445
        return msg;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   446
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   447
90ce3da70b43 Initial load
duke
parents:
diff changeset
   448
    /*
90ce3da70b43 Initial load
duke
parents:
diff changeset
   449
     * Returns the next DNS message from the TCP socket, or null on EOF.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   450
     */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   451
    private byte[] continueTcpQuery(Tcp tcp) throws IOException {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   452
90ce3da70b43 Initial load
duke
parents:
diff changeset
   453
        int lenHi = tcp.in.read();      // high-order byte of response length
90ce3da70b43 Initial load
duke
parents:
diff changeset
   454
        if (lenHi == -1) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   455
            return null;        // EOF
90ce3da70b43 Initial load
duke
parents:
diff changeset
   456
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   457
        int lenLo = tcp.in.read();      // low-order byte of response length
90ce3da70b43 Initial load
duke
parents:
diff changeset
   458
        if (lenLo == -1) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   459
            throw new IOException("Corrupted DNS response: bad length");
90ce3da70b43 Initial load
duke
parents:
diff changeset
   460
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   461
        int len = (lenHi << 8) | lenLo;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   462
        byte[] msg = new byte[len];
90ce3da70b43 Initial load
duke
parents:
diff changeset
   463
        int pos = 0;                    // next unfilled position in msg
90ce3da70b43 Initial load
duke
parents:
diff changeset
   464
        while (len > 0) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   465
            int n = tcp.in.read(msg, pos, len);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   466
            if (n == -1) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   467
                throw new IOException(
90ce3da70b43 Initial load
duke
parents:
diff changeset
   468
                        "Corrupted DNS response: too little data");
90ce3da70b43 Initial load
duke
parents:
diff changeset
   469
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   470
            len -= n;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   471
            pos += n;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   472
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   473
        return msg;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   474
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   475
90ce3da70b43 Initial load
duke
parents:
diff changeset
   476
    private Packet makeQueryPacket(DnsName fqdn, int xid,
90ce3da70b43 Initial load
duke
parents:
diff changeset
   477
                                   int qclass, int qtype, boolean recursion) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   478
        int qnameLen = fqdn.getOctets();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   479
        int pktLen = DNS_HDR_SIZE + qnameLen + 4;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   480
        Packet pkt = new Packet(pktLen);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   481
90ce3da70b43 Initial load
duke
parents:
diff changeset
   482
        short flags = recursion ? Header.RD_BIT : 0;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   483
90ce3da70b43 Initial load
duke
parents:
diff changeset
   484
        pkt.putShort(xid, IDENT_OFFSET);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   485
        pkt.putShort(flags, FLAGS_OFFSET);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   486
        pkt.putShort(1, NUMQ_OFFSET);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   487
        pkt.putShort(0, NUMANS_OFFSET);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   488
        pkt.putInt(0, NUMAUTH_OFFSET);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   489
90ce3da70b43 Initial load
duke
parents:
diff changeset
   490
        makeQueryName(fqdn, pkt, DNS_HDR_SIZE);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   491
        pkt.putShort(qtype, DNS_HDR_SIZE + qnameLen);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   492
        pkt.putShort(qclass, DNS_HDR_SIZE + qnameLen + 2);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   493
90ce3da70b43 Initial load
duke
parents:
diff changeset
   494
        return pkt;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   495
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   496
90ce3da70b43 Initial load
duke
parents:
diff changeset
   497
    // Builds a query name in pkt according to the RFC spec.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   498
    private void makeQueryName(DnsName fqdn, Packet pkt, int off) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   499
90ce3da70b43 Initial load
duke
parents:
diff changeset
   500
        // Loop through labels, least-significant first.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   501
        for (int i = fqdn.size() - 1; i >= 0; i--) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   502
            String label = fqdn.get(i);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   503
            int len = label.length();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   504
90ce3da70b43 Initial load
duke
parents:
diff changeset
   505
            pkt.putByte(len, off++);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   506
            for (int j = 0; j < len; j++) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   507
                pkt.putByte(label.charAt(j), off++);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   508
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   509
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   510
        if (!fqdn.hasRootLabel()) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   511
            pkt.putByte(0, off);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   512
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   513
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   514
90ce3da70b43 Initial load
duke
parents:
diff changeset
   515
    //-------------------------------------------------------------------------
90ce3da70b43 Initial load
duke
parents:
diff changeset
   516
90ce3da70b43 Initial load
duke
parents:
diff changeset
   517
    private byte[] lookupResponse(Integer xid) throws NamingException {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   518
        //
90ce3da70b43 Initial load
duke
parents:
diff changeset
   519
        // Check the queued responses: some other thread in between
90ce3da70b43 Initial load
duke
parents:
diff changeset
   520
        // received the response for this request.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   521
        //
90ce3da70b43 Initial load
duke
parents:
diff changeset
   522
        if (debug) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   523
            dprint("LOOKUP for: " + xid +
90ce3da70b43 Initial load
duke
parents:
diff changeset
   524
                "\tResponse Q:" + resps);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   525
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   526
        byte[] pkt;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   527
        if ((pkt = (byte[]) resps.get(xid)) != null) {
5624
302c8bd0d942 6955783: ServiceUnavailableException caught even the secondary DNS is available
weijun
parents: 2
diff changeset
   528
            checkResponseCode(new Header(pkt, pkt.length));
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   529
            synchronized (queuesLock) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   530
                resps.remove(xid);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   531
                reqs.remove(xid);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   532
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   533
90ce3da70b43 Initial load
duke
parents:
diff changeset
   534
            if (debug) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   535
                dprint("FOUND (" + Thread.currentThread() +
90ce3da70b43 Initial load
duke
parents:
diff changeset
   536
                    ") for:" + xid);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   537
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   538
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   539
        return pkt;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   540
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   541
90ce3da70b43 Initial load
duke
parents:
diff changeset
   542
    /*
90ce3da70b43 Initial load
duke
parents:
diff changeset
   543
     * Checks the header of an incoming DNS response.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   544
     * Returns true if it matches the given xid and throws a naming
90ce3da70b43 Initial load
duke
parents:
diff changeset
   545
     * exception, if appropriate, based on the response code.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   546
     */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   547
    private boolean isMatchResponse(byte[] pkt, int xid)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   548
                throws NamingException {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   549
90ce3da70b43 Initial load
duke
parents:
diff changeset
   550
        Header hdr = new Header(pkt, pkt.length);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   551
        if (hdr.query) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   552
            throw new CommunicationException("DNS error: expecting response");
90ce3da70b43 Initial load
duke
parents:
diff changeset
   553
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   554
90ce3da70b43 Initial load
duke
parents:
diff changeset
   555
        if (!reqs.contains(xid)) { // already received, ignore the response
90ce3da70b43 Initial load
duke
parents:
diff changeset
   556
            return false;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   557
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   558
90ce3da70b43 Initial load
duke
parents:
diff changeset
   559
        // common case- the request sent matches the subsequent response read
90ce3da70b43 Initial load
duke
parents:
diff changeset
   560
        if (hdr.xid == xid) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   561
            if (debug) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   562
                dprint("XID MATCH:" + xid);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   563
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   564
5624
302c8bd0d942 6955783: ServiceUnavailableException caught even the secondary DNS is available
weijun
parents: 2
diff changeset
   565
            checkResponseCode(hdr);
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   566
            // remove the response for the xid if received by some other thread.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   567
            synchronized (queuesLock) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   568
                resps.remove(xid);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   569
                reqs.remove(xid);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   570
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   571
            return true;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   572
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   573
90ce3da70b43 Initial load
duke
parents:
diff changeset
   574
        //
90ce3da70b43 Initial load
duke
parents:
diff changeset
   575
        // xid mis-match: enqueue the response, it may belong to some other
90ce3da70b43 Initial load
duke
parents:
diff changeset
   576
        // thread that has not yet had a chance to read its response.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   577
        // enqueue only the first response, responses for retries are ignored.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   578
        //
90ce3da70b43 Initial load
duke
parents:
diff changeset
   579
        synchronized (queuesLock) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   580
            if (reqs.contains(xid)) { // enqueue only the first response
90ce3da70b43 Initial load
duke
parents:
diff changeset
   581
                resps.put(xid, pkt);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   582
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   583
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   584
90ce3da70b43 Initial load
duke
parents:
diff changeset
   585
        if (debug) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   586
            dprint("NO-MATCH SEND ID:" +
90ce3da70b43 Initial load
duke
parents:
diff changeset
   587
                                xid + " RECVD ID:" + hdr.xid +
90ce3da70b43 Initial load
duke
parents:
diff changeset
   588
                                "    Response Q:" + resps +
90ce3da70b43 Initial load
duke
parents:
diff changeset
   589
                                "    Reqs size:" + reqs.size());
90ce3da70b43 Initial load
duke
parents:
diff changeset
   590
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   591
        return false;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   592
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   593
90ce3da70b43 Initial load
duke
parents:
diff changeset
   594
    /*
90ce3da70b43 Initial load
duke
parents:
diff changeset
   595
     * Throws an exception if appropriate for the response code of a
90ce3da70b43 Initial load
duke
parents:
diff changeset
   596
     * given header.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   597
     */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   598
    private void checkResponseCode(Header hdr) throws NamingException {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   599
90ce3da70b43 Initial load
duke
parents:
diff changeset
   600
        int rcode = hdr.rcode;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   601
        if (rcode == NO_ERROR) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   602
            return;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   603
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   604
        String msg = (rcode < rcodeDescription.length)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   605
            ? rcodeDescription[rcode]
90ce3da70b43 Initial load
duke
parents:
diff changeset
   606
            : "DNS error";
90ce3da70b43 Initial load
duke
parents:
diff changeset
   607
        msg += " [response code " + rcode + "]";
90ce3da70b43 Initial load
duke
parents:
diff changeset
   608
90ce3da70b43 Initial load
duke
parents:
diff changeset
   609
        switch (rcode) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   610
        case SERVER_FAILURE:
90ce3da70b43 Initial load
duke
parents:
diff changeset
   611
            throw new ServiceUnavailableException(msg);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   612
        case NAME_ERROR:
90ce3da70b43 Initial load
duke
parents:
diff changeset
   613
            throw new NameNotFoundException(msg);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   614
        case NOT_IMPL:
90ce3da70b43 Initial load
duke
parents:
diff changeset
   615
        case REFUSED:
90ce3da70b43 Initial load
duke
parents:
diff changeset
   616
            throw new OperationNotSupportedException(msg);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   617
        case FORMAT_ERROR:
90ce3da70b43 Initial load
duke
parents:
diff changeset
   618
        default:
90ce3da70b43 Initial load
duke
parents:
diff changeset
   619
            throw new NamingException(msg);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   620
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   621
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   622
90ce3da70b43 Initial load
duke
parents:
diff changeset
   623
    //-------------------------------------------------------------------------
90ce3da70b43 Initial load
duke
parents:
diff changeset
   624
90ce3da70b43 Initial load
duke
parents:
diff changeset
   625
    private static boolean debug = false;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   626
90ce3da70b43 Initial load
duke
parents:
diff changeset
   627
    public static void setDebug(boolean flag) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   628
        debug = flag;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   629
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   630
90ce3da70b43 Initial load
duke
parents:
diff changeset
   631
    private static void dprint(String mess) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   632
        if (debug) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   633
            System.err.println("DNS: " + mess);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   634
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   635
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   636
90ce3da70b43 Initial load
duke
parents:
diff changeset
   637
}
90ce3da70b43 Initial load
duke
parents:
diff changeset
   638
90ce3da70b43 Initial load
duke
parents:
diff changeset
   639
class Tcp {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   640
90ce3da70b43 Initial load
duke
parents:
diff changeset
   641
    private Socket sock;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   642
    java.io.InputStream in;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   643
    java.io.OutputStream out;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   644
90ce3da70b43 Initial load
duke
parents:
diff changeset
   645
    Tcp(InetAddress server, int port) throws IOException {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   646
        sock = new Socket(server, port);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   647
        sock.setTcpNoDelay(true);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   648
        out = new java.io.BufferedOutputStream(sock.getOutputStream());
90ce3da70b43 Initial load
duke
parents:
diff changeset
   649
        in = new java.io.BufferedInputStream(sock.getInputStream());
90ce3da70b43 Initial load
duke
parents:
diff changeset
   650
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   651
90ce3da70b43 Initial load
duke
parents:
diff changeset
   652
    void close() throws IOException {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   653
        sock.close();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   654
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   655
}
90ce3da70b43 Initial load
duke
parents:
diff changeset
   656
90ce3da70b43 Initial load
duke
parents:
diff changeset
   657
/*
90ce3da70b43 Initial load
duke
parents:
diff changeset
   658
 * javaos emulation -cj
90ce3da70b43 Initial load
duke
parents:
diff changeset
   659
 */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   660
class Packet {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   661
        byte buf[];
90ce3da70b43 Initial load
duke
parents:
diff changeset
   662
90ce3da70b43 Initial load
duke
parents:
diff changeset
   663
        Packet(int len) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   664
                buf = new byte[len];
90ce3da70b43 Initial load
duke
parents:
diff changeset
   665
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   666
90ce3da70b43 Initial load
duke
parents:
diff changeset
   667
        Packet(byte data[], int len) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   668
                buf = new byte[len];
90ce3da70b43 Initial load
duke
parents:
diff changeset
   669
                System.arraycopy(data, 0, buf, 0, len);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   670
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   671
90ce3da70b43 Initial load
duke
parents:
diff changeset
   672
        void putInt(int x, int off) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   673
                buf[off + 0] = (byte)(x >> 24);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   674
                buf[off + 1] = (byte)(x >> 16);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   675
                buf[off + 2] = (byte)(x >> 8);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   676
                buf[off + 3] = (byte)x;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   677
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   678
90ce3da70b43 Initial load
duke
parents:
diff changeset
   679
        void putShort(int x, int off) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   680
                buf[off + 0] = (byte)(x >> 8);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   681
                buf[off + 1] = (byte)x;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   682
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   683
90ce3da70b43 Initial load
duke
parents:
diff changeset
   684
        void putByte(int x, int off) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   685
                buf[off] = (byte)x;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   686
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   687
90ce3da70b43 Initial load
duke
parents:
diff changeset
   688
        void putBytes(byte src[], int src_offset, int dst_offset, int len) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   689
                System.arraycopy(src, src_offset, buf, dst_offset, len);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   690
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   691
90ce3da70b43 Initial load
duke
parents:
diff changeset
   692
        int length() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   693
                return buf.length;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   694
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   695
90ce3da70b43 Initial load
duke
parents:
diff changeset
   696
        byte[] getData() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   697
                return buf;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   698
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   699
}