Question.java

  1package de.measite.minidns;
  2
  3import java.io.ByteArrayOutputStream;
  4import java.io.DataInputStream;
  5import java.io.DataOutputStream;
  6import java.io.IOException;
  7import java.util.Arrays;
  8
  9import de.measite.minidns.Record.CLASS;
 10import de.measite.minidns.Record.TYPE;
 11import de.measite.minidns.util.NameUtil;
 12
 13/**
 14 * A DNS question (request).
 15 */
 16public class Question {
 17
 18    /**
 19     * The question string (e.g. "measite.de").
 20     */
 21    private final String name;
 22
 23    /**
 24     * The question type (e.g. A).
 25     */
 26    private final TYPE type;
 27
 28    /**
 29     * The question class (usually IN / internet).
 30     */
 31    private final CLASS clazz;
 32
 33    /**
 34     * UnicastQueries have the highest bit of the CLASS field set to 1.
 35     */
 36    private final boolean unicastQuery;
 37
 38    /**
 39     * Cache for the serialized object.
 40     */
 41    private byte[] byteArray;
 42
 43    /**
 44     * Create a dns question for the given name/type/class.
 45     * @param name The name e.g. "measite.de".
 46     * @param type The type, e.g. A.
 47     * @param clazz The class, usually IN (internet).
 48     */
 49    public Question(String name, TYPE type, CLASS clazz, boolean unicastQuery) {
 50        this.name = name;
 51        this.type = type;
 52        this.clazz = clazz;
 53        this.unicastQuery = unicastQuery;
 54    }
 55
 56    /**
 57     * Create a dns question for the given name/type/class.
 58     * @param name The name e.g. "measite.de".
 59     * @param type The type, e.g. A.
 60     * @param clazz The class, usually IN (internet).
 61     */
 62    public Question(String name, TYPE type, CLASS clazz) {
 63        this(name, type, clazz, false);
 64    }
 65
 66    /**
 67     * Create a dns question for the given name/type/IN (internet class).
 68     * @param name The name e.g. "measite.de".
 69     * @param type The type, e.g. A.
 70     */
 71    public Question(String name, TYPE type) {
 72        this(name, type, CLASS.IN);
 73    }
 74
 75    /**
 76     * Retrieve the type of this question.
 77     * @return The type.
 78     */
 79    public TYPE getType() {
 80        return type;
 81    }
 82
 83    /**
 84     * Retrieve the class of this dns question (usually internet).
 85     * @return The class of this dns question.
 86     */
 87    public CLASS getClazz() {
 88        return clazz;
 89    }
 90
 91    /**
 92     * Retrieve the name of this dns question (e.g. "measite.de").
 93     * @return The name of this dns question.
 94     */
 95    public String getName() {
 96        return name;
 97    }
 98
 99    /**
100     * Parse a byte array and rebuild the dns question from it.
101     * @param dis The input stream.
102     * @param data The plain data (for dns name references).
103     * @return The parsed dns question.
104     * @throws IOException On errors (read outside of packet).
105     */
106    public static Question parse(DataInputStream dis, byte[] data) throws IOException {
107        String name = NameUtil.parse(dis, data);
108        TYPE type = TYPE.getType(dis.readUnsignedShort());
109        CLASS clazz = CLASS.getClass(dis.readUnsignedShort());
110        return new Question (name, type, clazz);
111    }
112
113    /**
114     * Generate a binary paket for this dns question.
115     * @return The dns question.
116     */
117    public byte[] toByteArray() {
118        if (byteArray == null) {
119            ByteArrayOutputStream baos = new ByteArrayOutputStream(512);
120            DataOutputStream dos = new DataOutputStream(baos);
121
122            try {
123                dos.write(NameUtil.toByteArray(this.name));
124                dos.writeShort(type.getValue());
125                dos.writeShort(clazz.getValue() | (unicastQuery ? (1 << 15) : 0));
126                dos.flush();
127            } catch (IOException e) {
128                // Should never happen
129                throw new IllegalStateException(e);
130            }
131            byteArray = baos.toByteArray();
132        }
133        return byteArray;
134    }
135
136    @Override
137    public int hashCode() {
138        return Arrays.hashCode(toByteArray());
139    }
140
141    @Override
142    public boolean equals(Object other) {
143        if (this == other) {
144            return true;
145        }
146        if (!(other instanceof Question)) {
147            return false;
148        }
149        byte t[] = toByteArray();
150        byte o[] = ((Question)other).toByteArray();
151        return Arrays.equals(t, o);
152    }
153
154    @Override
155    public String toString() {
156        return "Question/" + clazz + "/" + type + ": " + name;
157    }
158}