/** * */ package javax.jmdns.impl; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.LinkedList; import java.util.List; import javax.jmdns.impl.constants.DNSConstants; /** * DNSMessage define a DNS message either incoming or outgoing. * * @author Werner Randelshofer, Rick Blair, Pierre Frisch */ public abstract class DNSMessage { /** * */ public static final boolean MULTICAST = true; /** * */ public static final boolean UNICAST = false; // protected DatagramPacket _packet; // protected int _off; // protected int _len; // protected byte[] _data; private int _id; boolean _multicast; private int _flags; protected final List<DNSQuestion> _questions; protected final List<DNSRecord> _answers; protected final List<DNSRecord> _authoritativeAnswers; protected final List<DNSRecord> _additionals; /** * @param flags * @param id * @param multicast */ protected DNSMessage(int flags, int id, boolean multicast) { super(); _flags = flags; _id = id; _multicast = multicast; _questions = Collections.synchronizedList(new LinkedList<DNSQuestion>()); _answers = Collections.synchronizedList(new LinkedList<DNSRecord>()); _authoritativeAnswers = Collections.synchronizedList(new LinkedList<DNSRecord>()); _additionals = Collections.synchronizedList(new LinkedList<DNSRecord>()); } // public DatagramPacket getPacket() { // return _packet; // } // // public int getOffset() { // return _off; // } // // public int getLength() { // return _len; // } // // public byte[] getData() { // if ( _data == null ) _data = new byte[DNSConstants.MAX_MSG_TYPICAL]; // return _data; // } /** * @return message id */ public int getId() { return (_multicast ? 0 : _id); } /** * @param id * the id to set */ public void setId(int id) { this._id = id; } /** * @return message flags */ public int getFlags() { return _flags; } /** * @param flags * the flags to set */ public void setFlags(int flags) { this._flags = flags; } /** * @return true if multicast */ public boolean isMulticast() { return _multicast; } /** * @return list of questions */ public Collection<? extends DNSQuestion> getQuestions() { return _questions; } /** * @return number of questions in the message */ public int getNumberOfQuestions() { return this.getQuestions().size(); } public Collection<? extends DNSRecord> getAllAnswers() { List<DNSRecord> aList = new ArrayList<DNSRecord>(_answers.size() + _authoritativeAnswers.size() + _additionals.size()); aList.addAll(_answers); aList.addAll(_authoritativeAnswers); aList.addAll(_additionals); return aList; } /** * @return list of answers */ public Collection<? extends DNSRecord> getAnswers() { return _answers; } /** * @return number of answers in the message */ public int getNumberOfAnswers() { return this.getAnswers().size(); } /** * @return list of authorities */ public Collection<? extends DNSRecord> getAuthorities() { return _authoritativeAnswers; } /** * @return number of authorities in the message */ public int getNumberOfAuthorities() { return this.getAuthorities().size(); } /** * @return list of additional answers */ public Collection<? extends DNSRecord> getAdditionals() { return _additionals; } /** * @return number of additional in the message */ public int getNumberOfAdditionals() { return this.getAdditionals().size(); } /** * Check if the message is truncated. * * @return true if the message was truncated */ public boolean isTruncated() { return (_flags & DNSConstants.FLAGS_TC) != 0; } /** * Check if the message is a query. * * @return true is the message is a query */ public boolean isQuery() { return (_flags & DNSConstants.FLAGS_QR_MASK) == DNSConstants.FLAGS_QR_QUERY; } /** * Check if the message is a response. * * @return true is the message is a response */ public boolean isResponse() { return (_flags & DNSConstants.FLAGS_QR_MASK) == DNSConstants.FLAGS_QR_RESPONSE; } /** * Check if the message is empty * * @return true is the message is empty */ public boolean isEmpty() { return (this.getNumberOfQuestions() + this.getNumberOfAnswers() + this.getNumberOfAuthorities() + this.getNumberOfAdditionals()) == 0; } /** * Debugging. */ String print() { StringBuffer buf = new StringBuffer(200); buf.append(this.toString()); buf.append("\n"); for (DNSQuestion question : _questions) { buf.append("\tquestion: "); buf.append(question); buf.append("\n"); } for (DNSRecord answer : _answers) { buf.append("\tanswer: "); buf.append(answer); buf.append("\n"); } for (DNSRecord answer : _authoritativeAnswers) { buf.append("\tauthoritative: "); buf.append(answer); buf.append("\n"); } for (DNSRecord answer : _additionals) { buf.append("\tadditional: "); buf.append(answer); buf.append("\n"); } return buf.toString(); } /** * Debugging. * * @param data * @return data dump */ protected String print(byte[] data) { StringBuilder buf = new StringBuilder(4000); for (int off = 0, len = data.length; off < len; off += 32) { int n = Math.min(32, len - off); if (off < 0x10) { buf.append(' '); } if (off < 0x100) { buf.append(' '); } if (off < 0x1000) { buf.append(' '); } buf.append(Integer.toHexString(off)); buf.append(':'); int index = 0; for (index = 0; index < n; index++) { if ((index % 8) == 0) { buf.append(' '); } buf.append(Integer.toHexString((data[off + index] & 0xF0) >> 4)); buf.append(Integer.toHexString((data[off + index] & 0x0F) >> 0)); } // for incomplete lines if (index < 32) { for (int i = index; i < 32; i++) { if ((i % 8) == 0) { buf.append(' '); } buf.append(" "); } } buf.append(" "); for (index = 0; index < n; index++) { if ((index % 8) == 0) { buf.append(' '); } int ch = data[off + index] & 0xFF; buf.append(((ch > ' ') && (ch < 127)) ? (char) ch : '.'); } buf.append("\n"); // limit message size if (off + 32 >= 2048) { buf.append("....\n"); break; } } return buf.toString(); } }