Conversations/libs/minidns/src/main/java/de/measite/minidns/Question.java

159 lines
4.2 KiB
Java

package de.measite.minidns;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.Arrays;
import de.measite.minidns.Record.CLASS;
import de.measite.minidns.Record.TYPE;
import de.measite.minidns.util.NameUtil;
/**
* A DNS question (request).
*/
public class Question {
/**
* The question string (e.g. "measite.de").
*/
private final String name;
/**
* The question type (e.g. A).
*/
private final TYPE type;
/**
* The question class (usually IN / internet).
*/
private final CLASS clazz;
/**
* UnicastQueries have the highest bit of the CLASS field set to 1.
*/
private final boolean unicastQuery;
/**
* Cache for the serialized object.
*/
private byte[] byteArray;
/**
* Create a dns question for the given name/type/class.
* @param name The name e.g. "measite.de".
* @param type The type, e.g. A.
* @param clazz The class, usually IN (internet).
*/
public Question(String name, TYPE type, CLASS clazz, boolean unicastQuery) {
this.name = name;
this.type = type;
this.clazz = clazz;
this.unicastQuery = unicastQuery;
}
/**
* Create a dns question for the given name/type/class.
* @param name The name e.g. "measite.de".
* @param type The type, e.g. A.
* @param clazz The class, usually IN (internet).
*/
public Question(String name, TYPE type, CLASS clazz) {
this(name, type, clazz, false);
}
/**
* Create a dns question for the given name/type/IN (internet class).
* @param name The name e.g. "measite.de".
* @param type The type, e.g. A.
*/
public Question(String name, TYPE type) {
this(name, type, CLASS.IN);
}
/**
* Retrieve the type of this question.
* @return The type.
*/
public TYPE getType() {
return type;
}
/**
* Retrieve the class of this dns question (usually internet).
* @return The class of this dns question.
*/
public CLASS getClazz() {
return clazz;
}
/**
* Retrieve the name of this dns question (e.g. "measite.de").
* @return The name of this dns question.
*/
public String getName() {
return name;
}
/**
* Parse a byte array and rebuild the dns question from it.
* @param dis The input stream.
* @param data The plain data (for dns name references).
* @return The parsed dns question.
* @throws IOException On errors (read outside of packet).
*/
public static Question parse(DataInputStream dis, byte[] data) throws IOException {
String name = NameUtil.parse(dis, data);
TYPE type = TYPE.getType(dis.readUnsignedShort());
CLASS clazz = CLASS.getClass(dis.readUnsignedShort());
return new Question (name, type, clazz);
}
/**
* Generate a binary paket for this dns question.
* @return The dns question.
*/
public byte[] toByteArray() {
if (byteArray == null) {
ByteArrayOutputStream baos = new ByteArrayOutputStream(512);
DataOutputStream dos = new DataOutputStream(baos);
try {
dos.write(NameUtil.toByteArray(this.name));
dos.writeShort(type.getValue());
dos.writeShort(clazz.getValue() | (unicastQuery ? (1 << 15) : 0));
dos.flush();
} catch (IOException e) {
// Should never happen
throw new IllegalStateException(e);
}
byteArray = baos.toByteArray();
}
return byteArray;
}
@Override
public int hashCode() {
return Arrays.hashCode(toByteArray());
}
@Override
public boolean equals(Object other) {
if (this == other) {
return true;
}
if (!(other instanceof Question)) {
return false;
}
byte t[] = toByteArray();
byte o[] = ((Question)other).toByteArray();
return Arrays.equals(t, o);
}
@Override
public String toString() {
return "Question/" + clazz + "/" + type + ": " + name;
}
}