13742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman// Copyright 2003-2005 Arthur van Hoff, Rick Blair 23742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman// Licensed under Apache License version 2.0 33742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman// Original license LGPL 43742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 53742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanpackage javax.jmdns.impl; 63742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 73742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport java.io.ByteArrayOutputStream; 83742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport java.io.IOException; 93742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport java.util.HashMap; 103742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport java.util.Map; 113742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 123742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport javax.jmdns.impl.constants.DNSConstants; 133742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport javax.jmdns.impl.constants.DNSRecordClass; 143742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 153742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman/** 163742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * An outgoing DNS message. 173742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * 183742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * @author Arthur van Hoff, Rick Blair, Werner Randelshofer 193742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 203742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanpublic final class DNSOutgoing extends DNSMessage { 213742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 223742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public static class MessageOutputStream extends ByteArrayOutputStream { 233742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman private final DNSOutgoing _out; 243742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 253742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman private final int _offset; 263742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 273742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 283742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * Creates a new message stream, with a buffer capacity of the specified size, in bytes. 293742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * 303742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * @param size 313742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * the initial size. 323742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * @exception IllegalArgumentException 333742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * if size is negative. 343742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 353742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman MessageOutputStream(int size, DNSOutgoing out) { 363742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman this(size, out, 0); 373742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 383742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 393742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman MessageOutputStream(int size, DNSOutgoing out, int offset) { 403742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman super(size); 413742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman _out = out; 423742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman _offset = offset; 433742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 443742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 453742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman void writeByte(int value) { 463742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman this.write(value & 0xFF); 473742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 483742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 493742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman void writeBytes(String str, int off, int len) { 503742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman for (int i = 0; i < len; i++) { 513742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman writeByte(str.charAt(off + i)); 523742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 533742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 543742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 553742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman void writeBytes(byte data[]) { 563742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (data != null) { 573742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman writeBytes(data, 0, data.length); 583742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 593742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 603742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 613742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman void writeBytes(byte data[], int off, int len) { 623742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman for (int i = 0; i < len; i++) { 633742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman writeByte(data[off + i]); 643742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 653742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 663742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 673742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman void writeShort(int value) { 683742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman writeByte(value >> 8); 693742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman writeByte(value); 703742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 713742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 723742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman void writeInt(int value) { 733742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman writeShort(value >> 16); 743742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman writeShort(value); 753742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 763742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 773742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman void writeUTF(String str, int off, int len) { 783742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman // compute utf length 793742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman int utflen = 0; 803742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman for (int i = 0; i < len; i++) { 813742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman int ch = str.charAt(off + i); 823742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if ((ch >= 0x0001) && (ch <= 0x007F)) { 833742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman utflen += 1; 843742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } else { 853742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (ch > 0x07FF) { 863742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman utflen += 3; 873742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } else { 883742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman utflen += 2; 893742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 903742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 913742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 923742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman // write utf length 933742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman writeByte(utflen); 943742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman // write utf data 953742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman for (int i = 0; i < len; i++) { 963742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman int ch = str.charAt(off + i); 973742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if ((ch >= 0x0001) && (ch <= 0x007F)) { 983742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman writeByte(ch); 993742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } else { 1003742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (ch > 0x07FF) { 1013742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman writeByte(0xE0 | ((ch >> 12) & 0x0F)); 1023742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman writeByte(0x80 | ((ch >> 6) & 0x3F)); 1033742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman writeByte(0x80 | ((ch >> 0) & 0x3F)); 1043742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } else { 1053742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman writeByte(0xC0 | ((ch >> 6) & 0x1F)); 1063742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman writeByte(0x80 | ((ch >> 0) & 0x3F)); 1073742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 1083742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 1093742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 1103742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 1113742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 1123742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman void writeName(String name) { 1133742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman writeName(name, true); 1143742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 1153742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 1163742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman void writeName(String name, boolean useCompression) { 1173742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman String aName = name; 1183742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman while (true) { 1193742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman int n = aName.indexOf('.'); 1203742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (n < 0) { 1213742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman n = aName.length(); 1223742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 1233742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (n <= 0) { 1243742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman writeByte(0); 1253742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman return; 1263742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 1273742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman String label = aName.substring(0, n); 1283742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (useCompression && USE_DOMAIN_NAME_COMPRESSION) { 1293742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman Integer offset = _out._names.get(aName); 1303742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (offset != null) { 1313742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman int val = offset.intValue(); 1323742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman writeByte((val >> 8) | 0xC0); 1333742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman writeByte(val & 0xFF); 1343742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman return; 1353742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 1363742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman _out._names.put(aName, Integer.valueOf(this.size() + _offset)); 1373742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman writeUTF(label, 0, label.length()); 1383742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } else { 1393742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman writeUTF(label, 0, label.length()); 1403742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 1413742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman aName = aName.substring(n); 1423742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (aName.startsWith(".")) { 1433742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman aName = aName.substring(1); 1443742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 1453742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 1463742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 1473742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 1483742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman void writeQuestion(DNSQuestion question) { 1493742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman writeName(question.getName()); 1503742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman writeShort(question.getRecordType().indexValue()); 1513742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman writeShort(question.getRecordClass().indexValue()); 1523742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 1533742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 1543742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman void writeRecord(DNSRecord rec, long now) { 1553742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman writeName(rec.getName()); 1563742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman writeShort(rec.getRecordType().indexValue()); 1573742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman writeShort(rec.getRecordClass().indexValue() | ((rec.isUnique() && _out.isMulticast()) ? DNSRecordClass.CLASS_UNIQUE : 0)); 1583742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman writeInt((now == 0) ? rec.getTTL() : rec.getRemainingTTL(now)); 1593742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 1603742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman // We need to take into account the 2 size bytes 1613742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman MessageOutputStream record = new MessageOutputStream(512, _out, _offset + this.size() + 2); 1623742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman rec.write(record); 1633742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman byte[] byteArray = record.toByteArray(); 1643742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 1653742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman writeShort(byteArray.length); 1663742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman write(byteArray, 0, byteArray.length); 1673742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 1683742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 1693742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 1703742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 1713742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 1723742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * This can be used to turn off domain name compression. This was helpful for tracking problems interacting with other mdns implementations. 1733742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 1743742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public static boolean USE_DOMAIN_NAME_COMPRESSION = true; 1753742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 1763742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman Map<String, Integer> _names; 1773742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 1783742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman private int _maxUDPPayload; 1793742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 1803742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman private final MessageOutputStream _questionsBytes; 1813742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 1823742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman private final MessageOutputStream _answersBytes; 1833742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 1843742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman private final MessageOutputStream _authoritativeAnswersBytes; 1853742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 1863742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman private final MessageOutputStream _additionalsAnswersBytes; 1873742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 1883742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman private final static int HEADER_SIZE = 12; 1893742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 1903742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 1913742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * Create an outgoing multicast query or response. 1923742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * 1933742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * @param flags 1943742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 1953742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public DNSOutgoing(int flags) { 1963742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman this(flags, true, DNSConstants.MAX_MSG_TYPICAL); 1973742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 1983742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 1993742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 2003742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * Create an outgoing query or response. 2013742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * 2023742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * @param flags 2033742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * @param multicast 2043742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 2053742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public DNSOutgoing(int flags, boolean multicast) { 2063742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman this(flags, multicast, DNSConstants.MAX_MSG_TYPICAL); 2073742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 2083742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 2093742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 2103742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * Create an outgoing query or response. 2113742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * 2123742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * @param flags 2133742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * @param multicast 2143742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * @param senderUDPPayload 2153742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * 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. 2163742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 2173742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public DNSOutgoing(int flags, boolean multicast, int senderUDPPayload) { 2183742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman super(flags, 0, multicast); 2193742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman _names = new HashMap<String, Integer>(); 2203742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman _maxUDPPayload = (senderUDPPayload > 0 ? senderUDPPayload : DNSConstants.MAX_MSG_TYPICAL); 2213742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman _questionsBytes = new MessageOutputStream(senderUDPPayload, this); 2223742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman _answersBytes = new MessageOutputStream(senderUDPPayload, this); 2233742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman _authoritativeAnswersBytes = new MessageOutputStream(senderUDPPayload, this); 2243742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman _additionalsAnswersBytes = new MessageOutputStream(senderUDPPayload, this); 2253742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 2263742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 2273742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 2283742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * Return the number of byte available in the message. 2293742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * 2303742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * @return available space 2313742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 2323742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public int availableSpace() { 2333742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman return _maxUDPPayload - HEADER_SIZE - _questionsBytes.size() - _answersBytes.size() - _authoritativeAnswersBytes.size() - _additionalsAnswersBytes.size(); 2343742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 2353742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 2363742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 2373742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * Add a question to the message. 2383742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * 2393742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * @param rec 2403742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * @exception IOException 2413742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 2423742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public void addQuestion(DNSQuestion rec) throws IOException { 2433742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman MessageOutputStream record = new MessageOutputStream(512, this); 2443742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman record.writeQuestion(rec); 2453742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman byte[] byteArray = record.toByteArray(); 2463742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (byteArray.length < this.availableSpace()) { 2473742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman _questions.add(rec); 2483742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman _questionsBytes.write(byteArray, 0, byteArray.length); 2493742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } else { 2503742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman throw new IOException("message full"); 2513742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 2523742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 2533742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 2543742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 2553742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * Add an answer if it is not suppressed. 2563742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * 2573742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * @param in 2583742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * @param rec 2593742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * @exception IOException 2603742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 2613742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public void addAnswer(DNSIncoming in, DNSRecord rec) throws IOException { 2623742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if ((in == null) || !rec.suppressedBy(in)) { 2633742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman this.addAnswer(rec, 0); 2643742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 2653742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 2663742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 2673742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 2683742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * Add an answer to the message. 2693742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * 2703742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * @param rec 2713742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * @param now 2723742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * @exception IOException 2733742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 2743742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public void addAnswer(DNSRecord rec, long now) throws IOException { 2753742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (rec != null) { 2763742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if ((now == 0) || !rec.isExpired(now)) { 2773742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman MessageOutputStream record = new MessageOutputStream(512, this); 2783742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman record.writeRecord(rec, now); 2793742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman byte[] byteArray = record.toByteArray(); 2803742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (byteArray.length < this.availableSpace()) { 2813742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman _answers.add(rec); 2823742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman _answersBytes.write(byteArray, 0, byteArray.length); 2833742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } else { 2843742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman throw new IOException("message full"); 2853742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 2863742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 2873742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 2883742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 2893742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 2903742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 2913742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * Add an authoritative answer to the message. 2923742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * 2933742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * @param rec 2943742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * @exception IOException 2953742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 2963742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public void addAuthorativeAnswer(DNSRecord rec) throws IOException { 2973742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman MessageOutputStream record = new MessageOutputStream(512, this); 2983742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman record.writeRecord(rec, 0); 2993742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman byte[] byteArray = record.toByteArray(); 3003742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (byteArray.length < this.availableSpace()) { 3013742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman _authoritativeAnswers.add(rec); 3023742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman _authoritativeAnswersBytes.write(byteArray, 0, byteArray.length); 3033742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } else { 3043742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman throw new IOException("message full"); 3053742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 3063742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 3073742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 3083742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 3093742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * Add an additional answer to the record. Omit if there is no room. 3103742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * 3113742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * @param in 3123742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * @param rec 3133742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * @exception IOException 3143742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 3153742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public void addAdditionalAnswer(DNSIncoming in, DNSRecord rec) throws IOException { 3163742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman MessageOutputStream record = new MessageOutputStream(512, this); 3173742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman record.writeRecord(rec, 0); 3183742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman byte[] byteArray = record.toByteArray(); 3193742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (byteArray.length < this.availableSpace()) { 3203742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman _additionals.add(rec); 3213742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman _additionalsAnswersBytes.write(byteArray, 0, byteArray.length); 3223742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } else { 3233742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman throw new IOException("message full"); 3243742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 3253742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 3263742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 3273742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 3283742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * Builds the final message buffer to be send and returns it. 3293742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * 3303742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * @return bytes to send. 3313742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 3323742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public byte[] data() { 3333742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman long now = System.currentTimeMillis(); // System.currentTimeMillis() 3343742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman _names.clear(); 3353742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 3363742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman MessageOutputStream message = new MessageOutputStream(_maxUDPPayload, this); 3373742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman message.writeShort(_multicast ? 0 : this.getId()); 3383742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman message.writeShort(this.getFlags()); 3393742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman message.writeShort(this.getNumberOfQuestions()); 3403742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman message.writeShort(this.getNumberOfAnswers()); 3413742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman message.writeShort(this.getNumberOfAuthorities()); 3423742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman message.writeShort(this.getNumberOfAdditionals()); 3433742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman for (DNSQuestion question : _questions) { 3443742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman message.writeQuestion(question); 3453742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 3463742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman for (DNSRecord record : _answers) { 3473742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman message.writeRecord(record, now); 3483742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 3493742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman for (DNSRecord record : _authoritativeAnswers) { 3503742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman message.writeRecord(record, now); 3513742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 3523742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman for (DNSRecord record : _additionals) { 3533742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman message.writeRecord(record, now); 3543742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 3553742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman return message.toByteArray(); 3563742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 3573742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 3583742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman @Override 3593742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public boolean isQuery() { 3603742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman return (this.getFlags() & DNSConstants.FLAGS_QR_MASK) == DNSConstants.FLAGS_QR_QUERY; 3613742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 3623742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 3633742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 3643742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * Debugging. 3653742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 3663742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman String print(boolean dump) { 3673742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman StringBuilder buf = new StringBuilder(); 3683742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman buf.append(this.print()); 3693742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (dump) { 3703742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman buf.append(this.print(this.data())); 3713742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 3723742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman return buf.toString(); 3733742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 3743742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 3753742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman @Override 3763742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public String toString() { 3773742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman StringBuffer buf = new StringBuffer(); 3783742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman buf.append(isQuery() ? "dns[query:" : "dns[response:"); 3793742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman buf.append(" id=0x"); 3803742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman buf.append(Integer.toHexString(this.getId())); 3813742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (this.getFlags() != 0) { 3823742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman buf.append(", flags=0x"); 3833742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman buf.append(Integer.toHexString(this.getFlags())); 3843742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if ((this.getFlags() & DNSConstants.FLAGS_QR_RESPONSE) != 0) { 3853742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman buf.append(":r"); 3863742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 3873742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if ((this.getFlags() & DNSConstants.FLAGS_AA) != 0) { 3883742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman buf.append(":aa"); 3893742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 3903742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if ((this.getFlags() & DNSConstants.FLAGS_TC) != 0) { 3913742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman buf.append(":tc"); 3923742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 3933742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 3943742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (this.getNumberOfQuestions() > 0) { 3953742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman buf.append(", questions="); 3963742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman buf.append(this.getNumberOfQuestions()); 3973742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 3983742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (this.getNumberOfAnswers() > 0) { 3993742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman buf.append(", answers="); 4003742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman buf.append(this.getNumberOfAnswers()); 4013742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 4023742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (this.getNumberOfAuthorities() > 0) { 4033742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman buf.append(", authorities="); 4043742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman buf.append(this.getNumberOfAuthorities()); 4053742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 4063742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (this.getNumberOfAdditionals() > 0) { 4073742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman buf.append(", additionals="); 4083742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman buf.append(this.getNumberOfAdditionals()); 4093742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 4103742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (this.getNumberOfQuestions() > 0) { 4113742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman buf.append("\nquestions:"); 4123742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman for (DNSQuestion question : _questions) { 4133742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman buf.append("\n\t"); 4143742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman buf.append(question); 4153742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 4163742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 4173742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (this.getNumberOfAnswers() > 0) { 4183742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman buf.append("\nanswers:"); 4193742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman for (DNSRecord record : _answers) { 4203742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman buf.append("\n\t"); 4213742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman buf.append(record); 4223742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 4233742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 4243742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (this.getNumberOfAuthorities() > 0) { 4253742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman buf.append("\nauthorities:"); 4263742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman for (DNSRecord record : _authoritativeAnswers) { 4273742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman buf.append("\n\t"); 4283742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman buf.append(record); 4293742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 4303742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 4313742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (this.getNumberOfAdditionals() > 0) { 4323742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman buf.append("\nadditionals:"); 4333742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman for (DNSRecord record : _additionals) { 4343742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman buf.append("\n\t"); 4353742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman buf.append(record); 4363742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 4373742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 4383742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman buf.append("\nnames="); 4393742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman buf.append(_names); 4403742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman buf.append("]"); 4413742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman return buf.toString(); 4423742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 4433742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 4443742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 4453742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * @return the maxUDPPayload 4463742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 4473742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public int getMaxUDPPayload() { 4483742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman return this._maxUDPPayload; 4493742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 4503742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 4513742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman} 452