blob: d0ff6f3778f82ad6a8b8803cf21466f2665c07c9 [file] [log] [blame]
// Copyright 2003-2005 Arthur van Hoff, Rick Blair
// Licensed under Apache License version 2.0
// Original license LGPL
package javax.jmdns.impl;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.jmdns.ServiceEvent;
import javax.jmdns.ServiceInfo;
import javax.jmdns.ServiceInfo.Fields;
import javax.jmdns.impl.DNSOutgoing.MessageOutputStream;
import javax.jmdns.impl.constants.DNSConstants;
import javax.jmdns.impl.constants.DNSRecordClass;
import javax.jmdns.impl.constants.DNSRecordType;
/**
* DNS record
*
* @author Arthur van Hoff, Rick Blair, Werner Randelshofer, Pierre Frisch
*/
public abstract class DNSRecord extends DNSEntry {
private static Logger logger = Logger.getLogger(DNSRecord.class.getName());
private int _ttl;
private long _created;
/**
* This source is mainly for debugging purposes, should be the address that sent this record.
*/
private InetAddress _source;
/**
* Create a DNSRecord with a name, type, class, and ttl.
*/
DNSRecord(String name, DNSRecordType type, DNSRecordClass recordClass, boolean unique, int ttl) {
super(name, type, recordClass, unique);
this._ttl = ttl;
this._created = System.currentTimeMillis();
}
/*
* (non-Javadoc)
* @see javax.jmdns.impl.DNSEntry#equals(java.lang.Object)
*/
@Override
public boolean equals(Object other) {
return (other instanceof DNSRecord) && super.equals(other) && sameValue((DNSRecord) other);
}
/**
* True if this record has the same value as some other record.
*/
abstract boolean sameValue(DNSRecord other);
/**
* True if this record has the same type as some other record.
*/
boolean sameType(DNSRecord other) {
return this.getRecordType() == other.getRecordType();
}
/**
* Handles a query represented by this record.
*
* @return Returns true if a conflict with one of the services registered with JmDNS or with the hostname occured.
*/
abstract boolean handleQuery(JmDNSImpl dns, long expirationTime);
/**
* Handles a response represented by this record.
*
* @return Returns true if a conflict with one of the services registered with JmDNS or with the hostname occured.
*/
abstract boolean handleResponse(JmDNSImpl dns);
/**
* Adds this as an answer to the provided outgoing datagram.
*/
abstract DNSOutgoing addAnswer(JmDNSImpl dns, DNSIncoming in, InetAddress addr, int port, DNSOutgoing out) throws IOException;
/**
* True if this record is suppressed by the answers in a message.
*/
boolean suppressedBy(DNSIncoming msg) {
try {
for (DNSRecord answer : msg.getAllAnswers()) {
if (suppressedBy(answer)) {
return true;
}
}
return false;
} catch (ArrayIndexOutOfBoundsException e) {
logger.log(Level.WARNING, "suppressedBy() message " + msg + " exception ", e);
// msg.print(true);
return false;
}
}
/**
* True if this record would be suppressed by an answer. This is the case if this record would not have a significantly longer TTL.
*/
boolean suppressedBy(DNSRecord other) {
if (this.equals(other) && (other._ttl > _ttl / 2)) {
return true;
}
return false;
}
/**
* Get the expiration time of this record.
*/
long getExpirationTime(int percent) {
// ttl is in seconds the constant 10 is 1000 ms / 100 %
return _created + (percent * _ttl * 10L);
}
/**
* Get the remaining TTL for this record.
*/
int getRemainingTTL(long now) {
return (int) Math.max(0, (getExpirationTime(100) - now) / 1000);
}
/*
* (non-Javadoc)
* @see javax.jmdns.impl.DNSEntry#isExpired(long)
*/
@Override
public boolean isExpired(long now) {
return getExpirationTime(100) <= now;
}
/*
* (non-Javadoc)
* @see javax.jmdns.impl.DNSEntry#isStale(long)
*/
@Override
public boolean isStale(long now) {
return getExpirationTime(50) <= now;
}
/**
* Reset the TTL of a record. This avoids having to update the entire record in the cache.
*/
void resetTTL(DNSRecord other) {
_created = other._created;
_ttl = other._ttl;
}
/**
* When a record flushed we don't remove it immediately, but mark it for rapid decay.
*/
void setWillExpireSoon(long now) {
_created = now;
_ttl = DNSConstants.RECORD_EXPIRY_DELAY;
}
/**
* Write this record into an outgoing message.
*/
abstract void write(MessageOutputStream out);
public static class IPv4Address extends Address {
IPv4Address(String name, DNSRecordClass recordClass, boolean unique, int ttl, InetAddress addr) {
super(name, DNSRecordType.TYPE_A, recordClass, unique, ttl, addr);
}
IPv4Address(String name, DNSRecordClass recordClass, boolean unique, int ttl, byte[] rawAddress) {
super(name, DNSRecordType.TYPE_A, recordClass, unique, ttl, rawAddress);
}
@Override
void write(MessageOutputStream out) {
if (_addr != null) {
byte[] buffer = _addr.getAddress();
// If we have a type A records we should answer with a IPv4 address
if (_addr instanceof Inet4Address) {
// All is good
} else {
// Get the last four bytes
byte[] tempbuffer = buffer;
buffer = new byte[4];
System.arraycopy(tempbuffer, 12, buffer, 0, 4);
}
int length = buffer.length;
out.writeBytes(buffer, 0, length);
}
}
/*
* (non-Javadoc)
* @see javax.jmdns.impl.DNSRecord#getServiceInfo(boolean)
*/
@Override
public ServiceInfo getServiceInfo(boolean persistent) {
ServiceInfoImpl info = (ServiceInfoImpl) super.getServiceInfo(persistent);
info.addAddress((Inet4Address) _addr);
return info;
}
}
public static class IPv6Address extends Address {
IPv6Address(String name, DNSRecordClass recordClass, boolean unique, int ttl, InetAddress addr) {
super(name, DNSRecordType.TYPE_AAAA, recordClass, unique, ttl, addr);
}
IPv6Address(String name, DNSRecordClass recordClass, boolean unique, int ttl, byte[] rawAddress) {
super(name, DNSRecordType.TYPE_AAAA, recordClass, unique, ttl, rawAddress);
}
@Override
void write(MessageOutputStream out) {
if (_addr != null) {
byte[] buffer = _addr.getAddress();
// If we have a type AAAA records we should answer with a IPv6 address
if (_addr instanceof Inet4Address) {
byte[] tempbuffer = buffer;
buffer = new byte[16];
for (int i = 0; i < 16; i++) {
if (i < 11) {
buffer[i] = tempbuffer[i - 12];
} else {
buffer[i] = 0;
}
}
}
int length = buffer.length;
out.writeBytes(buffer, 0, length);
}
}
/*
* (non-Javadoc)
* @see javax.jmdns.impl.DNSRecord#getServiceInfo(boolean)
*/
@Override
public ServiceInfo getServiceInfo(boolean persistent) {
ServiceInfoImpl info = (ServiceInfoImpl) super.getServiceInfo(persistent);
info.addAddress((Inet6Address) _addr);
return info;
}
}
/**
* Address record.
*/
public static abstract class Address extends DNSRecord {
private static Logger logger1 = Logger.getLogger(Address.class.getName());
InetAddress _addr;
protected Address(String name, DNSRecordType type, DNSRecordClass recordClass, boolean unique, int ttl, InetAddress addr) {
super(name, type, recordClass, unique, ttl);
this._addr = addr;
}
protected Address(String name, DNSRecordType type, DNSRecordClass recordClass, boolean unique, int ttl, byte[] rawAddress) {
super(name, type, recordClass, unique, ttl);
try {
this._addr = InetAddress.getByAddress(rawAddress);
} catch (UnknownHostException exception) {
logger1.log(Level.WARNING, "Address() exception ", exception);
}
}
boolean same(DNSRecord other) {
if (! (other instanceof Address) ) {
return false;
}
return ((sameName(other)) && ((sameValue(other))));
}
boolean sameName(DNSRecord other) {
return this.getName().equalsIgnoreCase(other.getName());
}
@Override
boolean sameValue(DNSRecord other) {
if (! (other instanceof Address) ) {
return false;
}
Address address = (Address) other;
if ((this.getAddress() == null) && (address.getAddress() != null)) {
return false;
}
return this.getAddress().equals(address.getAddress());
}
@Override
public boolean isSingleValued() {
return false;
}
InetAddress getAddress() {
return _addr;
}
/**
* Creates a byte array representation of this record. This is needed for tie-break tests according to draft-cheshire-dnsext-multicastdns-04.txt chapter 9.2.
*/
@Override
protected void toByteArray(DataOutputStream dout) throws IOException {
super.toByteArray(dout);
byte[] buffer = this.getAddress().getAddress();
for (int i = 0; i < buffer.length; i++) {
dout.writeByte(buffer[i]);
}
}
/**
* Does the necessary actions, when this as a query.
*/
@Override
boolean handleQuery(JmDNSImpl dns, long expirationTime) {
if (dns.getLocalHost().conflictWithRecord(this)) {
DNSRecord.Address localAddress = dns.getLocalHost().getDNSAddressRecord(this.getRecordType(), this.isUnique(), DNSConstants.DNS_TTL);
int comparison = this.compareTo(localAddress);
if (comparison == 0) {
// the 2 records are identical this probably means we are seeing our own record.
// With multiple interfaces on a single computer it is possible to see our
// own records come in on different interfaces than the ones they were sent on.
// see section "10. Conflict Resolution" of mdns draft spec.
logger1.finer("handleQuery() Ignoring an identical address query");
return false;
}
logger1.finer("handleQuery() Conflicting query detected.");
// Tie breaker test
if (dns.isProbing() && comparison > 0) {
// We lost the tie-break. We have to choose a different name.
dns.getLocalHost().incrementHostName();
dns.getCache().clear();
for (ServiceInfo serviceInfo : dns.getServices().values()) {
ServiceInfoImpl info = (ServiceInfoImpl) serviceInfo;
info.revertState();
}
}
dns.revertState();
return true;
}
return false;
}
/**
* Does the necessary actions, when this as a response.
*/
@Override
boolean handleResponse(JmDNSImpl dns) {
if (dns.getLocalHost().conflictWithRecord(this)) {
logger1.finer("handleResponse() Denial detected");
if (dns.isProbing()) {
dns.getLocalHost().incrementHostName();
dns.getCache().clear();
for (ServiceInfo serviceInfo : dns.getServices().values()) {
ServiceInfoImpl info = (ServiceInfoImpl) serviceInfo;
info.revertState();
}
}
dns.revertState();
return true;
}
return false;
}
@Override
DNSOutgoing addAnswer(JmDNSImpl dns, DNSIncoming in, InetAddress addr, int port, DNSOutgoing out) throws IOException {
return out;
}
/*
* (non-Javadoc)
* @see javax.jmdns.impl.DNSRecord#getServiceInfo(boolean)
*/
@Override
public ServiceInfo getServiceInfo(boolean persistent) {
ServiceInfoImpl info = new ServiceInfoImpl(this.getQualifiedNameMap(), 0, 0, 0, persistent, (byte[]) null);
// info.setAddress(_addr); This is done in the sub class so we don't have to test for class type
return info;
}
/*
* (non-Javadoc)
* @see javax.jmdns.impl.DNSRecord#getServiceEvent(javax.jmdns.impl.JmDNSImpl)
*/
@Override
public ServiceEvent getServiceEvent(JmDNSImpl dns) {
ServiceInfo info = this.getServiceInfo(false);
((ServiceInfoImpl) info).setDns(dns);
return new ServiceEventImpl(dns, info.getType(), info.getName(), info);
}
/*
* (non-Javadoc)
* @see com.webobjects.discoveryservices.DNSRecord#toString(java.lang.StringBuilder)
*/
@Override
protected void toString(StringBuilder aLog) {
super.toString(aLog);
aLog.append(" address: '" + (this.getAddress() != null ? this.getAddress().getHostAddress() : "null") + "'");
}
}
/**
* Pointer record.
*/
public static class Pointer extends DNSRecord {
// private static Logger logger = Logger.getLogger(Pointer.class.getName());
private final String _alias;
public Pointer(String name, DNSRecordClass recordClass, boolean unique, int ttl, String alias) {
super(name, DNSRecordType.TYPE_PTR, recordClass, unique, ttl);
this._alias = alias;
}
/*
* (non-Javadoc)
* @see javax.jmdns.impl.DNSEntry#isSameEntry(javax.jmdns.impl.DNSEntry)
*/
@Override
public boolean isSameEntry(DNSEntry entry) {
return super.isSameEntry(entry) && (entry instanceof Pointer) && this.sameValue((Pointer) entry);
}
@Override
void write(MessageOutputStream out) {
out.writeName(_alias);
}
@Override
boolean sameValue(DNSRecord other) {
if (! (other instanceof Pointer) ) {
return false;
}
Pointer pointer = (Pointer) other;
if ((_alias == null) && (pointer._alias != null)) {
return false;
}
return _alias.equals(pointer._alias);
}
@Override
public boolean isSingleValued() {
return false;
}
@Override
boolean handleQuery(JmDNSImpl dns, long expirationTime) {
// Nothing to do (?)
// I think there is no possibility for conflicts for this record type?
return false;
}
@Override
boolean handleResponse(JmDNSImpl dns) {
// Nothing to do (?)
// I think there is no possibility for conflicts for this record type?
return false;
}
String getAlias() {
return _alias;
}
@Override
DNSOutgoing addAnswer(JmDNSImpl dns, DNSIncoming in, InetAddress addr, int port, DNSOutgoing out) throws IOException {
return out;
}
/*
* (non-Javadoc)
* @see javax.jmdns.impl.DNSRecord#getServiceInfo(boolean)
*/
@Override
public ServiceInfo getServiceInfo(boolean persistent) {
if (this.isServicesDiscoveryMetaQuery()) {
// The service name is in the alias
Map<Fields, String> map = ServiceInfoImpl.decodeQualifiedNameMapForType(this.getAlias());
return new ServiceInfoImpl(map, 0, 0, 0, persistent, (byte[]) null);
} else if (this.isReverseLookup()) {
return new ServiceInfoImpl(this.getQualifiedNameMap(), 0, 0, 0, persistent, (byte[]) null);
} else if (this.isDomainDiscoveryQuery()) {
// FIXME [PJYF Nov 16 2010] We do not currently support domain discovery
return new ServiceInfoImpl(this.getQualifiedNameMap(), 0, 0, 0, persistent, (byte[]) null);
}
Map<Fields, String> map = ServiceInfoImpl.decodeQualifiedNameMapForType(this.getAlias());
map.put(Fields.Subtype, this.getQualifiedNameMap().get(Fields.Subtype));
return new ServiceInfoImpl(map, 0, 0, 0, persistent, this.getAlias());
}
/*
* (non-Javadoc)
* @see javax.jmdns.impl.DNSRecord#getServiceEvent(javax.jmdns.impl.JmDNSImpl)
*/
@Override
public ServiceEvent getServiceEvent(JmDNSImpl dns) {
ServiceInfo info = this.getServiceInfo(false);
((ServiceInfoImpl) info).setDns(dns);
String domainName = info.getType();
String serviceName = JmDNSImpl.toUnqualifiedName(domainName, this.getAlias());
return new ServiceEventImpl(dns, domainName, serviceName, info);
}
/*
* (non-Javadoc)
* @see com.webobjects.discoveryservices.DNSRecord#toString(java.lang.StringBuilder)
*/
@Override
protected void toString(StringBuilder aLog) {
super.toString(aLog);
aLog.append(" alias: '" + (_alias != null ? _alias.toString() : "null") + "'");
}
}
public final static byte[] EMPTY_TXT = new byte[] { 0 };
public static class Text extends DNSRecord {
// private static Logger logger = Logger.getLogger(Text.class.getName());
private final byte[] _text;
public Text(String name, DNSRecordClass recordClass, boolean unique, int ttl, byte text[]) {
super(name, DNSRecordType.TYPE_TXT, recordClass, unique, ttl);
this._text = (text != null && text.length > 0 ? text : EMPTY_TXT);
}
/**
* @return the text
*/
byte[] getText() {
return this._text;
}
@Override
void write(MessageOutputStream out) {
out.writeBytes(_text, 0, _text.length);
}
@Override
boolean sameValue(DNSRecord other) {
if (! (other instanceof Text) ) {
return false;
}
Text txt = (Text) other;
if ((_text == null) && (txt._text != null)) {
return false;
}
if (txt._text.length != _text.length) {
return false;
}
for (int i = _text.length; i-- > 0;) {
if (txt._text[i] != _text[i]) {
return false;
}
}
return true;
}
@Override
public boolean isSingleValued() {
return true;
}
@Override
boolean handleQuery(JmDNSImpl dns, long expirationTime) {
// Nothing to do (?)
// I think there is no possibility for conflicts for this record type?
return false;
}
@Override
boolean handleResponse(JmDNSImpl dns) {
// Nothing to do (?)
// Shouldn't we care if we get a conflict at this level?
/*
* ServiceInfo info = (ServiceInfo) dns.services.get(name.toLowerCase()); if (info != null) { if (! Arrays.equals(text,info.text)) { info.revertState(); return true; } }
*/
return false;
}
@Override
DNSOutgoing addAnswer(JmDNSImpl dns, DNSIncoming in, InetAddress addr, int port, DNSOutgoing out) throws IOException {
return out;
}
/*
* (non-Javadoc)
* @see javax.jmdns.impl.DNSRecord#getServiceInfo(boolean)
*/
@Override
public ServiceInfo getServiceInfo(boolean persistent) {
return new ServiceInfoImpl(this.getQualifiedNameMap(), 0, 0, 0, persistent, _text);
}
/*
* (non-Javadoc)
* @see javax.jmdns.impl.DNSRecord#getServiceEvent(javax.jmdns.impl.JmDNSImpl)
*/
@Override
public ServiceEvent getServiceEvent(JmDNSImpl dns) {
ServiceInfo info = this.getServiceInfo(false);
((ServiceInfoImpl) info).setDns(dns);
return new ServiceEventImpl(dns, info.getType(), info.getName(), info);
}
/*
* (non-Javadoc)
* @see com.webobjects.discoveryservices.DNSRecord#toString(java.lang.StringBuilder)
*/
@Override
protected void toString(StringBuilder aLog) {
super.toString(aLog);
aLog.append(" text: '" + ((_text.length > 20) ? new String(_text, 0, 17) + "..." : new String(_text)) + "'");
}
}
/**
* Service record.
*/
public static class Service extends DNSRecord {
private static Logger logger1 = Logger.getLogger(Service.class.getName());
private final int _priority;
private final int _weight;
private final int _port;
private final String _server;
public Service(String name, DNSRecordClass recordClass, boolean unique, int ttl, int priority, int weight, int port, String server) {
super(name, DNSRecordType.TYPE_SRV, recordClass, unique, ttl);
this._priority = priority;
this._weight = weight;
this._port = port;
this._server = server;
}
@Override
void write(MessageOutputStream out) {
out.writeShort(_priority);
out.writeShort(_weight);
out.writeShort(_port);
if (DNSIncoming.USE_DOMAIN_NAME_FORMAT_FOR_SRV_TARGET) {
out.writeName(_server);
} else {
// [PJYF Nov 13 2010] Do we still need this? This looks really bad. All label are supposed to start by a length.
out.writeUTF(_server, 0, _server.length());
// add a zero byte to the end just to be safe, this is the strange form
// used by the BonjourConformanceTest
out.writeByte(0);
}
}
@Override
protected void toByteArray(DataOutputStream dout) throws IOException {
super.toByteArray(dout);
dout.writeShort(_priority);
dout.writeShort(_weight);
dout.writeShort(_port);
try {
dout.write(_server.getBytes("UTF-8"));
} catch (UnsupportedEncodingException exception) {
/* UTF-8 is always present */
}
}
String getServer() {
return _server;
}
/**
* @return the priority
*/
public int getPriority() {
return this._priority;
}
/**
* @return the weight
*/
public int getWeight() {
return this._weight;
}
/**
* @return the port
*/
public int getPort() {
return this._port;
}
@Override
boolean sameValue(DNSRecord other) {
if (! (other instanceof Service) ) {
return false;
}
Service s = (Service) other;
return (_priority == s._priority) && (_weight == s._weight) && (_port == s._port) && _server.equals(s._server);
}
@Override
public boolean isSingleValued() {
return true;
}
@Override
boolean handleQuery(JmDNSImpl dns, long expirationTime) {
ServiceInfoImpl info = (ServiceInfoImpl) dns.getServices().get(this.getKey());
if (info != null && (info.isAnnouncing() || info.isAnnounced()) && (_port != info.getPort() || !_server.equalsIgnoreCase(dns.getLocalHost().getName()))) {
logger1.finer("handleQuery() Conflicting probe detected from: " + getRecordSource());
DNSRecord.Service localService = new DNSRecord.Service(info.getQualifiedName(), DNSRecordClass.CLASS_IN, DNSRecordClass.UNIQUE, DNSConstants.DNS_TTL, info.getPriority(), info.getWeight(), info.getPort(), dns.getLocalHost().getName());
// This block is useful for debugging race conditions when jmdns is responding to itself.
try {
if (dns.getInetAddress().equals(getRecordSource())) {
logger1.warning("Got conflicting probe from ourselves\n" + "incoming: " + this.toString() + "\n" + "local : " + localService.toString());
}
} catch (IOException e) {
logger1.log(Level.WARNING, "IOException", e);
}
int comparison = this.compareTo(localService);
if (comparison == 0) {
// the 2 records are identical this probably means we are seeing our own record.
// With multiple interfaces on a single computer it is possible to see our
// own records come in on different interfaces than the ones they were sent on.
// see section "10. Conflict Resolution" of mdns draft spec.
logger1.finer("handleQuery() Ignoring a identical service query");
return false;
}
// Tie breaker test
if (info.isProbing() && comparison > 0) {
// We lost the tie break
String oldName = info.getQualifiedName().toLowerCase();
info.setName(dns.incrementName(info.getName()));
dns.getServices().remove(oldName);
dns.getServices().put(info.getQualifiedName().toLowerCase(), info);
logger1.finer("handleQuery() Lost tie break: new unique name chosen:" + info.getName());
// We revert the state to start probing again with the new name
info.revertState();
} else {
// We won the tie break, so this conflicting probe should be ignored
// See paragraph 3 of section 9.2 in mdns draft spec
return false;
}
return true;
}
return false;
}
@Override
boolean handleResponse(JmDNSImpl dns) {
ServiceInfoImpl info = (ServiceInfoImpl) dns.getServices().get(this.getKey());
if (info != null && (_port != info.getPort() || !_server.equalsIgnoreCase(dns.getLocalHost().getName()))) {
logger1.finer("handleResponse() Denial detected");
if (info.isProbing()) {
String oldName = info.getQualifiedName().toLowerCase();
info.setName(dns.incrementName(info.getName()));
dns.getServices().remove(oldName);
dns.getServices().put(info.getQualifiedName().toLowerCase(), info);
logger1.finer("handleResponse() New unique name chose:" + info.getName());
}
info.revertState();
return true;
}
return false;
}
@Override
DNSOutgoing addAnswer(JmDNSImpl dns, DNSIncoming in, InetAddress addr, int port, DNSOutgoing out) throws IOException {
ServiceInfoImpl info = (ServiceInfoImpl) dns.getServices().get(this.getKey());
if (info != null) {
if (this._port == info.getPort() != _server.equals(dns.getLocalHost().getName())) {
return dns.addAnswer(in, addr, port, out, new DNSRecord.Service(info.getQualifiedName(), DNSRecordClass.CLASS_IN, DNSRecordClass.UNIQUE, DNSConstants.DNS_TTL, info.getPriority(), info.getWeight(), info.getPort(), dns
.getLocalHost().getName()));
}
}
return out;
}
/*
* (non-Javadoc)
* @see javax.jmdns.impl.DNSRecord#getServiceInfo(boolean)
*/
@Override
public ServiceInfo getServiceInfo(boolean persistent) {
return new ServiceInfoImpl(this.getQualifiedNameMap(), _port, _weight, _priority, persistent, _server);
}
/*
* (non-Javadoc)
* @see javax.jmdns.impl.DNSRecord#getServiceEvent(javax.jmdns.impl.JmDNSImpl)
*/
@Override
public ServiceEvent getServiceEvent(JmDNSImpl dns) {
ServiceInfo info = this.getServiceInfo(false);
((ServiceInfoImpl) info).setDns(dns);
// String domainName = "";
// String serviceName = this.getServer();
// int index = serviceName.indexOf('.');
// if (index > 0)
// {
// serviceName = this.getServer().substring(0, index);
// if (index + 1 < this.getServer().length())
// domainName = this.getServer().substring(index + 1);
// }
// return new ServiceEventImpl(dns, domainName, serviceName, info);
return new ServiceEventImpl(dns, info.getType(), info.getName(), info);
}
/*
* (non-Javadoc)
* @see com.webobjects.discoveryservices.DNSRecord#toString(java.lang.StringBuilder)
*/
@Override
protected void toString(StringBuilder aLog) {
super.toString(aLog);
aLog.append(" server: '" + _server + ":" + _port + "'");
}
}
public static class HostInformation extends DNSRecord {
String _os;
String _cpu;
/**
* @param name
* @param recordClass
* @param unique
* @param ttl
* @param cpu
* @param os
*/
public HostInformation(String name, DNSRecordClass recordClass, boolean unique, int ttl, String cpu, String os) {
super(name, DNSRecordType.TYPE_HINFO, recordClass, unique, ttl);
_cpu = cpu;
_os = os;
}
/*
* (non-Javadoc)
* @see javax.jmdns.impl.DNSRecord#addAnswer(javax.jmdns.impl.JmDNSImpl, javax.jmdns.impl.DNSIncoming, java.net.InetAddress, int, javax.jmdns.impl.DNSOutgoing)
*/
@Override
DNSOutgoing addAnswer(JmDNSImpl dns, DNSIncoming in, InetAddress addr, int port, DNSOutgoing out) throws IOException {
return out;
}
/*
* (non-Javadoc)
* @see javax.jmdns.impl.DNSRecord#handleQuery(javax.jmdns.impl.JmDNSImpl, long)
*/
@Override
boolean handleQuery(JmDNSImpl dns, long expirationTime) {
return false;
}
/*
* (non-Javadoc)
* @see javax.jmdns.impl.DNSRecord#handleResponse(javax.jmdns.impl.JmDNSImpl)
*/
@Override
boolean handleResponse(JmDNSImpl dns) {
return false;
}
/*
* (non-Javadoc)
* @see javax.jmdns.impl.DNSRecord#sameValue(javax.jmdns.impl.DNSRecord)
*/
@Override
boolean sameValue(DNSRecord other) {
if (! (other instanceof HostInformation) ) {
return false;
}
HostInformation hinfo = (HostInformation) other;
if ((_cpu == null) && (hinfo._cpu != null)) {
return false;
}
if ((_os == null) && (hinfo._os != null)) {
return false;
}
return _cpu.equals(hinfo._cpu) && _os.equals(hinfo._os);
}
/*
* (non-Javadoc)
* @see javax.jmdns.impl.DNSRecord#isSingleValued()
*/
@Override
public boolean isSingleValued() {
return true;
}
/*
* (non-Javadoc)
* @see javax.jmdns.impl.DNSRecord#write(javax.jmdns.impl.DNSOutgoing)
*/
@Override
void write(MessageOutputStream out) {
String hostInfo = _cpu + " " + _os;
out.writeUTF(hostInfo, 0, hostInfo.length());
}
/*
* (non-Javadoc)
* @see javax.jmdns.impl.DNSRecord#getServiceInfo(boolean)
*/
@Override
public ServiceInfo getServiceInfo(boolean persistent) {
Map<String, String> hinfo = new HashMap<String, String>(2);
hinfo.put("cpu", _cpu);
hinfo.put("os", _os);
return new ServiceInfoImpl(this.getQualifiedNameMap(), 0, 0, 0, persistent, hinfo);
}
/*
* (non-Javadoc)
* @see javax.jmdns.impl.DNSRecord#getServiceEvent(javax.jmdns.impl.JmDNSImpl)
*/
@Override
public ServiceEvent getServiceEvent(JmDNSImpl dns) {
ServiceInfo info = this.getServiceInfo(false);
((ServiceInfoImpl) info).setDns(dns);
return new ServiceEventImpl(dns, info.getType(), info.getName(), info);
}
/*
* (non-Javadoc)
* @see com.webobjects.discoveryservices.DNSRecord#toString(java.lang.StringBuilder)
*/
@Override
protected void toString(StringBuilder aLog) {
super.toString(aLog);
aLog.append(" cpu: '" + _cpu + "' os: '" + _os + "'");
}
}
/**
* Determine if a record can have multiple values in the cache.
*
* @return <code>false</code> if this record can have multiple values in the cache, <code>true</code> otherwise.
*/
public abstract boolean isSingleValued();
/**
* Return a service information associated with that record if appropriate.
*
* @return service information
*/
public ServiceInfo getServiceInfo() {
return this.getServiceInfo(false);
}
/**
* Return a service information associated with that record if appropriate.
*
* @param persistent
* if <code>true</code> ServiceListener.resolveService will be called whenever new new information is received.
* @return service information
*/
public abstract ServiceInfo getServiceInfo(boolean persistent);
/**
* Creates and return a service event for this record.
*
* @param dns
* DNS serviced by this event
* @return service event
*/
public abstract ServiceEvent getServiceEvent(JmDNSImpl dns);
public void setRecordSource(InetAddress source) {
this._source = source;
}
public InetAddress getRecordSource() {
return _source;
}
/*
* (non-Javadoc)
* @see com.webobjects.discoveryservices.DNSRecord#toString(java.lang.StringBuilder)
*/
@Override
protected void toString(StringBuilder aLog) {
super.toString(aLog);
aLog.append(" ttl: '" + getRemainingTTL(System.currentTimeMillis()) + "/" + _ttl + "'");
}
public void setTTL(int ttl) {
this._ttl = ttl;
}
public int getTTL() {
return _ttl;
}
}