javax.jmdns.impl.DNSRecord Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jmdns Show documentation
Show all versions of jmdns Show documentation
JmDNS is a Java implementation of multi-cast DNS and can be used for service registration and discovery in local area networks. JmDNS is fully compatible with Apple's Bonjour.
The project was originally started in December 2002 by Arthur van Hoff at Strangeberry. In November 2003 the project was moved to SourceForge, and the name was changed from JRendezvous to JmDNS for legal reasons.
Many thanks to Stuart Cheshire for help and moral support.
The newest version!
// 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 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 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.getInterface().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 hinfo = new HashMap(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 false
if this record can have multiple values in the cache, true
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 true
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;
}
}