summaryrefslogtreecommitdiff
path: root/src/javax/jmdns/impl/DNSOutgoing.java
diff options
context:
space:
mode:
authorMike Lockwood <lockwood@google.com>2012-03-21 12:26:23 -0700
committerMike Lockwood <lockwood@google.com>2012-03-21 12:26:23 -0700
commitf4eb7466d5c09098f9dc54137ed3235e3c43fc9f (patch)
tree56e1bf5e433e60e3a18d5a9d08b7d55a64d8ae1d /src/javax/jmdns/impl/DNSOutgoing.java
parent19376825c9e562c188aef9ccd09a7220bd3c0a20 (diff)
parent76f0067cea0428b683cba2f187d81e723658f964 (diff)
downloadjmdns-1d9e801e656103f1e34ad3ea8f090dee8efeb7d0.tar.gz
Merge remote-tracking branch 'goog/ics-aah-exp'android-wear-n-preview-3android-wear-n-preview-2android-wear-n-preview-1android-wear-7.1.1_r1android-wear-5.1.1_r1android-wear-5.1.0_r1android-wear-5.0.0_r1android-sdk-support_r11android-sdk-4.4.2_r1.0.1android-sdk-4.4.2_r1android-n-preview-5android-n-preview-4android-n-preview-3android-n-preview-2android-n-preview-1android-n-iot-preview-2android-m-preview-2android-m-preview-1android-m-previewandroid-l-preview_r2android-cts-6.0_r9android-cts-6.0_r8android-cts-6.0_r7android-cts-6.0_r6android-cts-6.0_r5android-cts-6.0_r4android-cts-6.0_r32android-cts-6.0_r31android-cts-6.0_r30android-cts-6.0_r3android-cts-6.0_r29android-cts-6.0_r28android-cts-6.0_r27android-cts-6.0_r26android-cts-6.0_r25android-cts-6.0_r24android-cts-6.0_r23android-cts-6.0_r22android-cts-6.0_r21android-cts-6.0_r20android-cts-6.0_r2android-cts-6.0_r19android-cts-6.0_r18android-cts-6.0_r17android-cts-6.0_r16android-cts-6.0_r15android-cts-6.0_r14android-cts-6.0_r13android-cts-6.0_r12android-cts-6.0_r1android-cts-5.1_r9android-cts-5.1_r8android-cts-5.1_r7android-cts-5.1_r6android-cts-5.1_r5android-cts-5.1_r4android-cts-5.1_r3android-cts-5.1_r28android-cts-5.1_r27android-cts-5.1_r26android-cts-5.1_r25android-cts-5.1_r24android-cts-5.1_r23android-cts-5.1_r22android-cts-5.1_r21android-cts-5.1_r20android-cts-5.1_r2android-cts-5.1_r19android-cts-5.1_r18android-cts-5.1_r17android-cts-5.1_r16android-cts-5.1_r15android-cts-5.1_r14android-cts-5.1_r13android-cts-5.1_r10android-cts-5.1_r1android-cts-5.0_r9android-cts-5.0_r8android-cts-5.0_r7android-cts-5.0_r6android-cts-5.0_r5android-cts-5.0_r4android-cts-5.0_r3android-cts-4.4_r4android-cts-4.4_r1android-cts-4.2_r2android-cts-4.2_r1android-cts-4.1_r4android-cts-4.1_r2android-cts-4.1_r1android-6.0.1_r9android-6.0.1_r81android-6.0.1_r80android-6.0.1_r8android-6.0.1_r79android-6.0.1_r78android-6.0.1_r77android-6.0.1_r74android-6.0.1_r73android-6.0.1_r72android-6.0.1_r70android-6.0.1_r7android-6.0.1_r69android-6.0.1_r68android-6.0.1_r67android-6.0.1_r66android-6.0.1_r65android-6.0.1_r63android-6.0.1_r62android-6.0.1_r61android-6.0.1_r60android-6.0.1_r59android-6.0.1_r58android-6.0.1_r57android-6.0.1_r56android-6.0.1_r55android-6.0.1_r54android-6.0.1_r53android-6.0.1_r52android-6.0.1_r51android-6.0.1_r50android-6.0.1_r5android-6.0.1_r49android-6.0.1_r48android-6.0.1_r47android-6.0.1_r46android-6.0.1_r45android-6.0.1_r43android-6.0.1_r42android-6.0.1_r41android-6.0.1_r40android-6.0.1_r4android-6.0.1_r33android-6.0.1_r32android-6.0.1_r31android-6.0.1_r30android-6.0.1_r3android-6.0.1_r28android-6.0.1_r27android-6.0.1_r26android-6.0.1_r25android-6.0.1_r24android-6.0.1_r22android-6.0.1_r21android-6.0.1_r20android-6.0.1_r18android-6.0.1_r17android-6.0.1_r16android-6.0.1_r13android-6.0.1_r12android-6.0.1_r11android-6.0.1_r10android-6.0.1_r1android-6.0.0_r7android-6.0.0_r6android-6.0.0_r5android-6.0.0_r41android-6.0.0_r4android-6.0.0_r3android-6.0.0_r26android-6.0.0_r25android-6.0.0_r24android-6.0.0_r23android-6.0.0_r2android-6.0.0_r13android-6.0.0_r12android-6.0.0_r11android-6.0.0_r1android-5.1.1_r9android-5.1.1_r8android-5.1.1_r7android-5.1.1_r6android-5.1.1_r5android-5.1.1_r4android-5.1.1_r38android-5.1.1_r37android-5.1.1_r36android-5.1.1_r35android-5.1.1_r34android-5.1.1_r33android-5.1.1_r30android-5.1.1_r3android-5.1.1_r29android-5.1.1_r28android-5.1.1_r26android-5.1.1_r25android-5.1.1_r24android-5.1.1_r23android-5.1.1_r22android-5.1.1_r20android-5.1.1_r2android-5.1.1_r19android-5.1.1_r18android-5.1.1_r17android-5.1.1_r16android-5.1.1_r15android-5.1.1_r14android-5.1.1_r13android-5.1.1_r12android-5.1.1_r10android-5.1.1_r1android-5.1.0_r5android-5.1.0_r4android-5.1.0_r3android-5.1.0_r1android-5.0.2_r3android-5.0.2_r1android-5.0.1_r1android-5.0.0_r7android-5.0.0_r6android-5.0.0_r5.1android-5.0.0_r5android-5.0.0_r4android-5.0.0_r3android-5.0.0_r2android-5.0.0_r1android-4.4w_r1android-4.4_r1.2.0.1android-4.4_r1.2android-4.4_r1.1.0.1android-4.4_r1.1android-4.4_r1.0.1android-4.4_r1android-4.4_r0.9android-4.4_r0.8android-4.4_r0.7android-4.4.4_r2.0.1android-4.4.4_r2android-4.4.4_r1.0.1android-4.4.4_r1android-4.4.3_r1.1.0.1android-4.4.3_r1.1android-4.4.3_r1.0.1android-4.4.3_r1android-4.4.2_r2.0.1android-4.4.2_r2android-4.4.2_r1.0.1android-4.4.2_r1android-4.4.1_r1.0.1android-4.4.1_r1android-4.3_r3.1android-4.3_r3android-4.3_r2.3android-4.3_r2.2android-4.3_r2.1android-4.3_r2android-4.3_r1.1android-4.3_r1android-4.3_r0.9.1android-4.3_r0.9android-4.3.1_r1android-4.2_r1android-4.2.2_r1.2android-4.2.2_r1.1android-4.2.2_r1android-4.2.1_r1.2android-4.2.1_r1.1android-4.2.1_r1android-4.1.2_r2.1android-4.1.2_r2android-4.1.2_r1android-4.1.1_r6.1android-4.1.1_r6android-4.1.1_r5android-4.1.1_r4android-4.1.1_r3android-4.1.1_r2android-4.1.1_r1.1android-4.1.1_r1tools_r22.2tools_r22tools_r21nougat-mr1-wear-releasen-iot-preview-2master-soongmarshmallow-releasemarshmallow-mr3-releasemarshmallow-mr2-releasemarshmallow-mr1-releasemarshmallow-mr1-devmarshmallow-dr1.6-releasemarshmallow-dr1.5-releasemarshmallow-dr1.5-devmarshmallow-dr-releasemarshmallow-dr-dragon-releasemarshmallow-dr-devmarshmallow-devmarshmallow-cts-releaselollipop-wear-releaselollipop-releaselollipop-mr1-wfc-releaselollipop-mr1-releaselollipop-mr1-fi-releaselollipop-mr1-devlollipop-mr1-cts-releaselollipop-devlollipop-cts-releasel-previewkitkat-wearkitkat-releasekitkat-mr2.2-releasekitkat-mr2.1-releasekitkat-mr2-releasekitkat-mr1.1-releasekitkat-mr1-releasekitkat-devkitkat-cts-releasekitkat-cts-devjb-releasejb-mr2.0.0-releasejb-mr2.0-releasejb-mr2-releasejb-mr2-devjb-mr1.1-releasejb-mr1.1-dev-plus-aospjb-mr1.1-devjb-mr1-releasejb-mr1-dev-plus-aospjb-mr1-devjb-mr0-releasejb-devidea133-weekly-releaseidea133
Diffstat (limited to 'src/javax/jmdns/impl/DNSOutgoing.java')
-rw-r--r--src/javax/jmdns/impl/DNSOutgoing.java451
1 files changed, 451 insertions, 0 deletions
diff --git a/src/javax/jmdns/impl/DNSOutgoing.java b/src/javax/jmdns/impl/DNSOutgoing.java
new file mode 100644
index 0000000..c3ba24e
--- /dev/null
+++ b/src/javax/jmdns/impl/DNSOutgoing.java
@@ -0,0 +1,451 @@
+// 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.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.jmdns.impl.constants.DNSConstants;
+import javax.jmdns.impl.constants.DNSRecordClass;
+
+/**
+ * An outgoing DNS message.
+ *
+ * @author Arthur van Hoff, Rick Blair, Werner Randelshofer
+ */
+public final class DNSOutgoing extends DNSMessage {
+
+ public static class MessageOutputStream extends ByteArrayOutputStream {
+ private final DNSOutgoing _out;
+
+ private final int _offset;
+
+ /**
+ * Creates a new message stream, with a buffer capacity of the specified size, in bytes.
+ *
+ * @param size
+ * the initial size.
+ * @exception IllegalArgumentException
+ * if size is negative.
+ */
+ MessageOutputStream(int size, DNSOutgoing out) {
+ this(size, out, 0);
+ }
+
+ MessageOutputStream(int size, DNSOutgoing out, int offset) {
+ super(size);
+ _out = out;
+ _offset = offset;
+ }
+
+ void writeByte(int value) {
+ this.write(value & 0xFF);
+ }
+
+ void writeBytes(String str, int off, int len) {
+ for (int i = 0; i < len; i++) {
+ writeByte(str.charAt(off + i));
+ }
+ }
+
+ void writeBytes(byte data[]) {
+ if (data != null) {
+ writeBytes(data, 0, data.length);
+ }
+ }
+
+ void writeBytes(byte data[], int off, int len) {
+ for (int i = 0; i < len; i++) {
+ writeByte(data[off + i]);
+ }
+ }
+
+ void writeShort(int value) {
+ writeByte(value >> 8);
+ writeByte(value);
+ }
+
+ void writeInt(int value) {
+ writeShort(value >> 16);
+ writeShort(value);
+ }
+
+ void writeUTF(String str, int off, int len) {
+ // compute utf length
+ int utflen = 0;
+ for (int i = 0; i < len; i++) {
+ int ch = str.charAt(off + i);
+ if ((ch >= 0x0001) && (ch <= 0x007F)) {
+ utflen += 1;
+ } else {
+ if (ch > 0x07FF) {
+ utflen += 3;
+ } else {
+ utflen += 2;
+ }
+ }
+ }
+ // write utf length
+ writeByte(utflen);
+ // write utf data
+ for (int i = 0; i < len; i++) {
+ int ch = str.charAt(off + i);
+ if ((ch >= 0x0001) && (ch <= 0x007F)) {
+ writeByte(ch);
+ } else {
+ if (ch > 0x07FF) {
+ writeByte(0xE0 | ((ch >> 12) & 0x0F));
+ writeByte(0x80 | ((ch >> 6) & 0x3F));
+ writeByte(0x80 | ((ch >> 0) & 0x3F));
+ } else {
+ writeByte(0xC0 | ((ch >> 6) & 0x1F));
+ writeByte(0x80 | ((ch >> 0) & 0x3F));
+ }
+ }
+ }
+ }
+
+ void writeName(String name) {
+ writeName(name, true);
+ }
+
+ void writeName(String name, boolean useCompression) {
+ String aName = name;
+ while (true) {
+ int n = aName.indexOf('.');
+ if (n < 0) {
+ n = aName.length();
+ }
+ if (n <= 0) {
+ writeByte(0);
+ return;
+ }
+ String label = aName.substring(0, n);
+ if (useCompression && USE_DOMAIN_NAME_COMPRESSION) {
+ Integer offset = _out._names.get(aName);
+ if (offset != null) {
+ int val = offset.intValue();
+ writeByte((val >> 8) | 0xC0);
+ writeByte(val & 0xFF);
+ return;
+ }
+ _out._names.put(aName, Integer.valueOf(this.size() + _offset));
+ writeUTF(label, 0, label.length());
+ } else {
+ writeUTF(label, 0, label.length());
+ }
+ aName = aName.substring(n);
+ if (aName.startsWith(".")) {
+ aName = aName.substring(1);
+ }
+ }
+ }
+
+ void writeQuestion(DNSQuestion question) {
+ writeName(question.getName());
+ writeShort(question.getRecordType().indexValue());
+ writeShort(question.getRecordClass().indexValue());
+ }
+
+ void writeRecord(DNSRecord rec, long now) {
+ writeName(rec.getName());
+ writeShort(rec.getRecordType().indexValue());
+ writeShort(rec.getRecordClass().indexValue() | ((rec.isUnique() && _out.isMulticast()) ? DNSRecordClass.CLASS_UNIQUE : 0));
+ writeInt((now == 0) ? rec.getTTL() : rec.getRemainingTTL(now));
+
+ // We need to take into account the 2 size bytes
+ MessageOutputStream record = new MessageOutputStream(512, _out, _offset + this.size() + 2);
+ rec.write(record);
+ byte[] byteArray = record.toByteArray();
+
+ writeShort(byteArray.length);
+ write(byteArray, 0, byteArray.length);
+ }
+
+ }
+
+ /**
+ * This can be used to turn off domain name compression. This was helpful for tracking problems interacting with other mdns implementations.
+ */
+ public static boolean USE_DOMAIN_NAME_COMPRESSION = true;
+
+ Map<String, Integer> _names;
+
+ private int _maxUDPPayload;
+
+ private final MessageOutputStream _questionsBytes;
+
+ private final MessageOutputStream _answersBytes;
+
+ private final MessageOutputStream _authoritativeAnswersBytes;
+
+ private final MessageOutputStream _additionalsAnswersBytes;
+
+ private final static int HEADER_SIZE = 12;
+
+ /**
+ * Create an outgoing multicast query or response.
+ *
+ * @param flags
+ */
+ public DNSOutgoing(int flags) {
+ this(flags, true, DNSConstants.MAX_MSG_TYPICAL);
+ }
+
+ /**
+ * Create an outgoing query or response.
+ *
+ * @param flags
+ * @param multicast
+ */
+ public DNSOutgoing(int flags, boolean multicast) {
+ this(flags, multicast, DNSConstants.MAX_MSG_TYPICAL);
+ }
+
+ /**
+ * Create an outgoing query or response.
+ *
+ * @param flags
+ * @param multicast
+ * @param senderUDPPayload
+ * The sender's UDP payload size is the number of bytes of the largest UDP payload that can be reassembled and delivered in the sender's network stack.
+ */
+ public DNSOutgoing(int flags, boolean multicast, int senderUDPPayload) {
+ super(flags, 0, multicast);
+ _names = new HashMap<String, Integer>();
+ _maxUDPPayload = (senderUDPPayload > 0 ? senderUDPPayload : DNSConstants.MAX_MSG_TYPICAL);
+ _questionsBytes = new MessageOutputStream(senderUDPPayload, this);
+ _answersBytes = new MessageOutputStream(senderUDPPayload, this);
+ _authoritativeAnswersBytes = new MessageOutputStream(senderUDPPayload, this);
+ _additionalsAnswersBytes = new MessageOutputStream(senderUDPPayload, this);
+ }
+
+ /**
+ * Return the number of byte available in the message.
+ *
+ * @return available space
+ */
+ public int availableSpace() {
+ return _maxUDPPayload - HEADER_SIZE - _questionsBytes.size() - _answersBytes.size() - _authoritativeAnswersBytes.size() - _additionalsAnswersBytes.size();
+ }
+
+ /**
+ * Add a question to the message.
+ *
+ * @param rec
+ * @exception IOException
+ */
+ public void addQuestion(DNSQuestion rec) throws IOException {
+ MessageOutputStream record = new MessageOutputStream(512, this);
+ record.writeQuestion(rec);
+ byte[] byteArray = record.toByteArray();
+ if (byteArray.length < this.availableSpace()) {
+ _questions.add(rec);
+ _questionsBytes.write(byteArray, 0, byteArray.length);
+ } else {
+ throw new IOException("message full");
+ }
+ }
+
+ /**
+ * Add an answer if it is not suppressed.
+ *
+ * @param in
+ * @param rec
+ * @exception IOException
+ */
+ public void addAnswer(DNSIncoming in, DNSRecord rec) throws IOException {
+ if ((in == null) || !rec.suppressedBy(in)) {
+ this.addAnswer(rec, 0);
+ }
+ }
+
+ /**
+ * Add an answer to the message.
+ *
+ * @param rec
+ * @param now
+ * @exception IOException
+ */
+ public void addAnswer(DNSRecord rec, long now) throws IOException {
+ if (rec != null) {
+ if ((now == 0) || !rec.isExpired(now)) {
+ MessageOutputStream record = new MessageOutputStream(512, this);
+ record.writeRecord(rec, now);
+ byte[] byteArray = record.toByteArray();
+ if (byteArray.length < this.availableSpace()) {
+ _answers.add(rec);
+ _answersBytes.write(byteArray, 0, byteArray.length);
+ } else {
+ throw new IOException("message full");
+ }
+ }
+ }
+ }
+
+ /**
+ * Add an authoritative answer to the message.
+ *
+ * @param rec
+ * @exception IOException
+ */
+ public void addAuthorativeAnswer(DNSRecord rec) throws IOException {
+ MessageOutputStream record = new MessageOutputStream(512, this);
+ record.writeRecord(rec, 0);
+ byte[] byteArray = record.toByteArray();
+ if (byteArray.length < this.availableSpace()) {
+ _authoritativeAnswers.add(rec);
+ _authoritativeAnswersBytes.write(byteArray, 0, byteArray.length);
+ } else {
+ throw new IOException("message full");
+ }
+ }
+
+ /**
+ * Add an additional answer to the record. Omit if there is no room.
+ *
+ * @param in
+ * @param rec
+ * @exception IOException
+ */
+ public void addAdditionalAnswer(DNSIncoming in, DNSRecord rec) throws IOException {
+ MessageOutputStream record = new MessageOutputStream(512, this);
+ record.writeRecord(rec, 0);
+ byte[] byteArray = record.toByteArray();
+ if (byteArray.length < this.availableSpace()) {
+ _additionals.add(rec);
+ _additionalsAnswersBytes.write(byteArray, 0, byteArray.length);
+ } else {
+ throw new IOException("message full");
+ }
+ }
+
+ /**
+ * Builds the final message buffer to be send and returns it.
+ *
+ * @return bytes to send.
+ */
+ public byte[] data() {
+ long now = System.currentTimeMillis(); // System.currentTimeMillis()
+ _names.clear();
+
+ MessageOutputStream message = new MessageOutputStream(_maxUDPPayload, this);
+ message.writeShort(_multicast ? 0 : this.getId());
+ message.writeShort(this.getFlags());
+ message.writeShort(this.getNumberOfQuestions());
+ message.writeShort(this.getNumberOfAnswers());
+ message.writeShort(this.getNumberOfAuthorities());
+ message.writeShort(this.getNumberOfAdditionals());
+ for (DNSQuestion question : _questions) {
+ message.writeQuestion(question);
+ }
+ for (DNSRecord record : _answers) {
+ message.writeRecord(record, now);
+ }
+ for (DNSRecord record : _authoritativeAnswers) {
+ message.writeRecord(record, now);
+ }
+ for (DNSRecord record : _additionals) {
+ message.writeRecord(record, now);
+ }
+ return message.toByteArray();
+ }
+
+ @Override
+ public boolean isQuery() {
+ return (this.getFlags() & DNSConstants.FLAGS_QR_MASK) == DNSConstants.FLAGS_QR_QUERY;
+ }
+
+ /**
+ * Debugging.
+ */
+ String print(boolean dump) {
+ StringBuilder buf = new StringBuilder();
+ buf.append(this.print());
+ if (dump) {
+ buf.append(this.print(this.data()));
+ }
+ return buf.toString();
+ }
+
+ @Override
+ public String toString() {
+ StringBuffer buf = new StringBuffer();
+ buf.append(isQuery() ? "dns[query:" : "dns[response:");
+ buf.append(" id=0x");
+ buf.append(Integer.toHexString(this.getId()));
+ if (this.getFlags() != 0) {
+ buf.append(", flags=0x");
+ buf.append(Integer.toHexString(this.getFlags()));
+ if ((this.getFlags() & DNSConstants.FLAGS_QR_RESPONSE) != 0) {
+ buf.append(":r");
+ }
+ if ((this.getFlags() & DNSConstants.FLAGS_AA) != 0) {
+ buf.append(":aa");
+ }
+ if ((this.getFlags() & DNSConstants.FLAGS_TC) != 0) {
+ buf.append(":tc");
+ }
+ }
+ if (this.getNumberOfQuestions() > 0) {
+ buf.append(", questions=");
+ buf.append(this.getNumberOfQuestions());
+ }
+ if (this.getNumberOfAnswers() > 0) {
+ buf.append(", answers=");
+ buf.append(this.getNumberOfAnswers());
+ }
+ if (this.getNumberOfAuthorities() > 0) {
+ buf.append(", authorities=");
+ buf.append(this.getNumberOfAuthorities());
+ }
+ if (this.getNumberOfAdditionals() > 0) {
+ buf.append(", additionals=");
+ buf.append(this.getNumberOfAdditionals());
+ }
+ if (this.getNumberOfQuestions() > 0) {
+ buf.append("\nquestions:");
+ for (DNSQuestion question : _questions) {
+ buf.append("\n\t");
+ buf.append(question);
+ }
+ }
+ if (this.getNumberOfAnswers() > 0) {
+ buf.append("\nanswers:");
+ for (DNSRecord record : _answers) {
+ buf.append("\n\t");
+ buf.append(record);
+ }
+ }
+ if (this.getNumberOfAuthorities() > 0) {
+ buf.append("\nauthorities:");
+ for (DNSRecord record : _authoritativeAnswers) {
+ buf.append("\n\t");
+ buf.append(record);
+ }
+ }
+ if (this.getNumberOfAdditionals() > 0) {
+ buf.append("\nadditionals:");
+ for (DNSRecord record : _additionals) {
+ buf.append("\n\t");
+ buf.append(record);
+ }
+ }
+ buf.append("\nnames=");
+ buf.append(_names);
+ buf.append("]");
+ return buf.toString();
+ }
+
+ /**
+ * @return the maxUDPPayload
+ */
+ public int getMaxUDPPayload() {
+ return this._maxUDPPayload;
+ }
+
+}