mirror of
https://github.com/openjdk/jdk.git
synced 2026-05-26 21:38:10 +00:00
206 lines
7.1 KiB
Java
206 lines
7.1 KiB
Java
/*
|
|
* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
|
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
*
|
|
* This code is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU General Public License version 2 only, as
|
|
* published by the Free Software Foundation. Oracle designates this
|
|
* particular file as subject to the "Classpath" exception as provided
|
|
* by Oracle in the LICENSE file that accompanied this code.
|
|
*
|
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
* version 2 for more details (a copy is included in the LICENSE file that
|
|
* accompanied this code).
|
|
*
|
|
* You should have received a copy of the GNU General Public License version
|
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*
|
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
|
* or visit www.oracle.com if you need additional information or have any
|
|
* questions.
|
|
*/
|
|
|
|
package com.sun.jndi.dns;
|
|
|
|
|
|
import java.lang.ref.SoftReference;
|
|
import java.util.Date;
|
|
import java.util.Vector;
|
|
|
|
|
|
/**
|
|
* ZoneNode extends NameNode to represent a tree of the zones in the
|
|
* DNS namespace, along with any intermediate nodes between zones.
|
|
* A ZoneNode that represents a zone may be "populated" with a
|
|
* NameNode tree containing the zone's contents.
|
|
*
|
|
* <p> A populated zone's contents will be flagged as having expired after
|
|
* the time specified by the minimum TTL value in the zone's SOA record.
|
|
*
|
|
* <p> Since zone cuts aren't directly modeled by a tree of ZoneNodes,
|
|
* ZoneNode.isZoneCut() always returns false.
|
|
*
|
|
* <p> The synchronization strategy is documented in DnsContext.java.
|
|
*
|
|
* <p> The zone's contents are accessed via a soft reference, so its
|
|
* heap space may be reclaimed when necessary. The zone may be
|
|
* repopulated later.
|
|
*
|
|
* @author Scott Seligman
|
|
*/
|
|
|
|
|
|
class ZoneNode extends NameNode {
|
|
|
|
private SoftReference<NameNode> contentsRef = null; // the zone's namespace
|
|
private long serialNumber = -1; // the zone data's serial number
|
|
private Date expiration = null; // time when the zone's data expires
|
|
|
|
ZoneNode(String label) {
|
|
super(label);
|
|
}
|
|
|
|
protected NameNode newNameNode(String label) {
|
|
return new ZoneNode(label);
|
|
}
|
|
|
|
/*
|
|
* Clears the contents of this node. If the node was flagged as
|
|
* expired, it remains so.
|
|
*/
|
|
synchronized void depopulate() {
|
|
contentsRef = null;
|
|
serialNumber = -1;
|
|
}
|
|
|
|
/*
|
|
* Is this node currently populated?
|
|
*/
|
|
synchronized boolean isPopulated() {
|
|
return (getContents() != null);
|
|
}
|
|
|
|
/*
|
|
* Returns the zone's contents, or null if the zone is not populated.
|
|
*/
|
|
synchronized NameNode getContents() {
|
|
return (contentsRef != null)
|
|
? contentsRef.get()
|
|
: null;
|
|
}
|
|
|
|
/*
|
|
* Has this zone's data expired?
|
|
*/
|
|
synchronized boolean isExpired() {
|
|
return ((expiration != null) && expiration.before(new Date()));
|
|
}
|
|
|
|
/*
|
|
* Returns the deepest populated zone on the path specified by a
|
|
* fully-qualified domain name, or null if there is no populated
|
|
* zone on that path. Note that a node may be depopulated after
|
|
* being returned.
|
|
*/
|
|
ZoneNode getDeepestPopulated(DnsName fqdn) {
|
|
ZoneNode znode = this;
|
|
ZoneNode popNode = isPopulated() ? this : null;
|
|
for (int i = 1; i < fqdn.size(); i++) { // "i=1" to skip root label
|
|
znode = (ZoneNode) znode.get(fqdn.getKey(i));
|
|
if (znode == null) {
|
|
break;
|
|
} else if (znode.isPopulated()) {
|
|
popNode = znode;
|
|
}
|
|
}
|
|
return popNode;
|
|
}
|
|
|
|
/*
|
|
* Populates (or repopulates) a zone given its own fully-qualified
|
|
* name and its resource records. Returns the zone's new contents.
|
|
*/
|
|
NameNode populate(DnsName zone, ResourceRecords rrs) {
|
|
// assert zone.get(0).equals(""); // zone has root label
|
|
// assert (zone.size() == (depth() + 1)); // +1 due to root label
|
|
|
|
NameNode newContents = new NameNode(null);
|
|
|
|
for (int i = 0; i < rrs.answer.size(); i++) {
|
|
ResourceRecord rr = rrs.answer.elementAt(i);
|
|
DnsName n = rr.getName();
|
|
|
|
// Ignore resource records whose names aren't within the zone's
|
|
// domain. Also skip records of the zone's top node, since
|
|
// the zone's root NameNode is already in place.
|
|
if ((n.size() > zone.size()) && n.startsWith(zone)) {
|
|
NameNode nnode = newContents.add(n, zone.size());
|
|
if (rr.getType() == ResourceRecord.TYPE_NS) {
|
|
nnode.setZoneCut(true);
|
|
}
|
|
}
|
|
}
|
|
// The zone's SOA record is the first record in the answer section.
|
|
ResourceRecord soa = rrs.answer.firstElement();
|
|
synchronized (this) {
|
|
contentsRef = new SoftReference<NameNode>(newContents);
|
|
serialNumber = getSerialNumber(soa);
|
|
setExpiration(getMinimumTtl(soa));
|
|
return newContents;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Set this zone's data to expire in <tt>secsToExpiration</tt> seconds.
|
|
*/
|
|
private void setExpiration(long secsToExpiration) {
|
|
expiration = new Date(System.currentTimeMillis() +
|
|
1000 * secsToExpiration);
|
|
}
|
|
|
|
/*
|
|
* Returns an SOA record's minimum TTL field.
|
|
*/
|
|
private static long getMinimumTtl(ResourceRecord soa) {
|
|
String rdata = (String) soa.getRdata();
|
|
int pos = rdata.lastIndexOf(' ') + 1;
|
|
return Long.parseLong(rdata.substring(pos));
|
|
}
|
|
|
|
/*
|
|
* Compares this zone's serial number with that of an SOA record.
|
|
* Zone must be populated.
|
|
* Returns a negative, zero, or positive integer as this zone's
|
|
* serial number is less than, equal to, or greater than the SOA
|
|
* record's.
|
|
* See ResourceRecord.compareSerialNumbers() for a description of
|
|
* serial number arithmetic.
|
|
*/
|
|
int compareSerialNumberTo(ResourceRecord soa) {
|
|
// assert isPopulated();
|
|
return ResourceRecord.compareSerialNumbers(serialNumber,
|
|
getSerialNumber(soa));
|
|
}
|
|
|
|
/*
|
|
* Returns an SOA record's serial number.
|
|
*/
|
|
private static long getSerialNumber(ResourceRecord soa) {
|
|
String rdata = (String) soa.getRdata();
|
|
|
|
// An SOA record ends with: serial refresh retry expire minimum.
|
|
// Set "beg" to the space before serial, and "end" to the space after.
|
|
// We go "backward" to avoid dealing with escaped spaces in names.
|
|
int beg = rdata.length();
|
|
int end = -1;
|
|
for (int i = 0; i < 5; i++) {
|
|
end = beg;
|
|
beg = rdata.lastIndexOf(' ', end - 1);
|
|
}
|
|
return Long.parseLong(rdata.substring(beg + 1, end));
|
|
}
|
|
}
|