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 * Cache for the serialized object.
35 */
36 private byte[] byteArray;
37
38 /**
39 * Create a dns question for the given name/type/class.
40 * @param name The name e.g. "measite.de".
41 * @param type The type, e.g. A.
42 * @param clazz The class, usually IN (internet).
43 */
44 public Question(String name, TYPE type, CLASS clazz) {
45 this.name = name;
46 this.type = type;
47 this.clazz = clazz;
48 }
49
50 /**
51 * Create a dns question for the given name/type/IN (internet class).
52 * @param name The name e.g. "measite.de".
53 * @param type The type, e.g. A.
54 */
55 public Question(String name, TYPE type) {
56 this(name, type, CLASS.IN);
57 }
58
59 /**
60 * Retrieve the type of this question.
61 * @return The type.
62 */
63 public TYPE getType() {
64 return type;
65 }
66
67 /**
68 * Retrieve the class of this dns question (usually internet).
69 * @return The class of this dns question.
70 */
71 public CLASS getClazz() {
72 return clazz;
73 }
74
75 /**
76 * Retrieve the name of this dns question (e.g. "measite.de").
77 * @return The name of this dns question.
78 */
79 public String getName() {
80 return name;
81 }
82
83 /**
84 * Parse a byte array and rebuild the dns question from it.
85 * @param dis The input stream.
86 * @param data The plain data (for dns name references).
87 * @return The parsed dns question.
88 * @throws IOException On errors (read outside of packet).
89 */
90 public static Question parse(DataInputStream dis, byte[] data) throws IOException {
91 String name = NameUtil.parse(dis, data);
92 TYPE type = TYPE.getType(dis.readUnsignedShort());
93 CLASS clazz = CLASS.getClass(dis.readUnsignedShort());
94 return new Question (name, type, clazz);
95 }
96
97 /**
98 * Generate a binary paket for this dns question.
99 * @return The dns question.
100 */
101 public byte[] toByteArray() {
102 if (byteArray == null) {
103 ByteArrayOutputStream baos = new ByteArrayOutputStream(512);
104 DataOutputStream dos = new DataOutputStream(baos);
105
106 try {
107 dos.write(NameUtil.toByteArray(this.name));
108 dos.writeShort(type.getValue());
109 dos.writeShort(clazz.getValue());
110 dos.flush();
111 } catch (IOException e) {
112 // Should never happen
113 throw new IllegalStateException(e);
114 }
115 byteArray = baos.toByteArray();
116 }
117 return byteArray;
118 }
119
120 @Override
121 public int hashCode() {
122 return Arrays.hashCode(toByteArray());
123 }
124
125 @Override
126 public boolean equals(Object other) {
127 if (this == other) {
128 return true;
129 }
130 if (!(other instanceof Question)) {
131 return false;
132 }
133 byte t[] = toByteArray();
134 byte o[] = ((Question)other).toByteArray();
135 return Arrays.equals(t, o);
136 }
137}