1/**
2 *
3 */
4package javax.jmdns.impl;
5
6import java.util.ArrayList;
7import java.util.Collection;
8import java.util.Collections;
9import java.util.LinkedList;
10import java.util.List;
11
12import javax.jmdns.impl.constants.DNSConstants;
13
14/**
15 * DNSMessage define a DNS message either incoming or outgoing.
16 *
17 * @author Werner Randelshofer, Rick Blair, Pierre Frisch
18 */
19public abstract class DNSMessage {
20
21    /**
22     *
23     */
24    public static final boolean       MULTICAST = true;
25
26    /**
27     *
28     */
29    public static final boolean       UNICAST   = false;
30
31    // protected DatagramPacket _packet;
32    // protected int _off;
33    // protected int _len;
34    // protected byte[] _data;
35
36    private int                       _id;
37
38    boolean                           _multicast;
39
40    private int                       _flags;
41
42    protected final List<DNSQuestion> _questions;
43
44    protected final List<DNSRecord>   _answers;
45
46    protected final List<DNSRecord>   _authoritativeAnswers;
47
48    protected final List<DNSRecord>   _additionals;
49
50    /**
51     * @param flags
52     * @param id
53     * @param multicast
54     */
55    protected DNSMessage(int flags, int id, boolean multicast) {
56        super();
57        _flags = flags;
58        _id = id;
59        _multicast = multicast;
60        _questions = Collections.synchronizedList(new LinkedList<DNSQuestion>());
61        _answers = Collections.synchronizedList(new LinkedList<DNSRecord>());
62        _authoritativeAnswers = Collections.synchronizedList(new LinkedList<DNSRecord>());
63        _additionals = Collections.synchronizedList(new LinkedList<DNSRecord>());
64    }
65
66    // public DatagramPacket getPacket() {
67    // return _packet;
68    // }
69    //
70    // public int getOffset() {
71    // return _off;
72    // }
73    //
74    // public int getLength() {
75    // return _len;
76    // }
77    //
78    // public byte[] getData() {
79    // if ( _data == null ) _data = new byte[DNSConstants.MAX_MSG_TYPICAL];
80    // return _data;
81    // }
82
83    /**
84     * @return message id
85     */
86    public int getId() {
87        return (_multicast ? 0 : _id);
88    }
89
90    /**
91     * @param id
92     *            the id to set
93     */
94    public void setId(int id) {
95        this._id = id;
96    }
97
98    /**
99     * @return message flags
100     */
101    public int getFlags() {
102        return _flags;
103    }
104
105    /**
106     * @param flags
107     *            the flags to set
108     */
109    public void setFlags(int flags) {
110        this._flags = flags;
111    }
112
113    /**
114     * @return true if multicast
115     */
116    public boolean isMulticast() {
117        return _multicast;
118    }
119
120    /**
121     * @return list of questions
122     */
123    public Collection<? extends DNSQuestion> getQuestions() {
124        return _questions;
125    }
126
127    /**
128     * @return number of questions in the message
129     */
130    public int getNumberOfQuestions() {
131        return this.getQuestions().size();
132    }
133
134    public Collection<? extends DNSRecord> getAllAnswers() {
135        List<DNSRecord> aList = new ArrayList<DNSRecord>(_answers.size() + _authoritativeAnswers.size() + _additionals.size());
136        aList.addAll(_answers);
137        aList.addAll(_authoritativeAnswers);
138        aList.addAll(_additionals);
139        return aList;
140    }
141
142    /**
143     * @return list of answers
144     */
145    public Collection<? extends DNSRecord> getAnswers() {
146        return _answers;
147    }
148
149    /**
150     * @return number of answers in the message
151     */
152    public int getNumberOfAnswers() {
153        return this.getAnswers().size();
154    }
155
156    /**
157     * @return list of authorities
158     */
159    public Collection<? extends DNSRecord> getAuthorities() {
160        return _authoritativeAnswers;
161    }
162
163    /**
164     * @return number of authorities in the message
165     */
166    public int getNumberOfAuthorities() {
167        return this.getAuthorities().size();
168    }
169
170    /**
171     * @return list of additional answers
172     */
173    public Collection<? extends DNSRecord> getAdditionals() {
174        return _additionals;
175    }
176
177    /**
178     * @return number of additional in the message
179     */
180    public int getNumberOfAdditionals() {
181        return this.getAdditionals().size();
182    }
183
184    /**
185     * Check if the message is truncated.
186     *
187     * @return true if the message was truncated
188     */
189    public boolean isTruncated() {
190        return (_flags & DNSConstants.FLAGS_TC) != 0;
191    }
192
193    /**
194     * Check if the message is a query.
195     *
196     * @return true is the message is a query
197     */
198    public boolean isQuery() {
199        return (_flags & DNSConstants.FLAGS_QR_MASK) == DNSConstants.FLAGS_QR_QUERY;
200    }
201
202    /**
203     * Check if the message is a response.
204     *
205     * @return true is the message is a response
206     */
207    public boolean isResponse() {
208        return (_flags & DNSConstants.FLAGS_QR_MASK) == DNSConstants.FLAGS_QR_RESPONSE;
209    }
210
211    /**
212     * Check if the message is empty
213     *
214     * @return true is the message is empty
215     */
216    public boolean isEmpty() {
217        return (this.getNumberOfQuestions() + this.getNumberOfAnswers() + this.getNumberOfAuthorities() + this.getNumberOfAdditionals()) == 0;
218    }
219
220    /**
221     * Debugging.
222     */
223    String print() {
224        StringBuffer buf = new StringBuffer(200);
225        buf.append(this.toString());
226        buf.append("\n");
227        for (DNSQuestion question : _questions) {
228            buf.append("\tquestion:      ");
229            buf.append(question);
230            buf.append("\n");
231        }
232        for (DNSRecord answer : _answers) {
233            buf.append("\tanswer:        ");
234            buf.append(answer);
235            buf.append("\n");
236        }
237        for (DNSRecord answer : _authoritativeAnswers) {
238            buf.append("\tauthoritative: ");
239            buf.append(answer);
240            buf.append("\n");
241        }
242        for (DNSRecord answer : _additionals) {
243            buf.append("\tadditional:    ");
244            buf.append(answer);
245            buf.append("\n");
246        }
247        return buf.toString();
248    }
249
250    /**
251     * Debugging.
252     *
253     * @param data
254     * @return data dump
255     */
256    protected String print(byte[] data) {
257        StringBuilder buf = new StringBuilder(4000);
258        for (int off = 0, len = data.length; off < len; off += 32) {
259            int n = Math.min(32, len - off);
260            if (off < 0x10) {
261                buf.append(' ');
262            }
263            if (off < 0x100) {
264                buf.append(' ');
265            }
266            if (off < 0x1000) {
267                buf.append(' ');
268            }
269            buf.append(Integer.toHexString(off));
270            buf.append(':');
271            int index = 0;
272            for (index = 0; index < n; index++) {
273                if ((index % 8) == 0) {
274                    buf.append(' ');
275                }
276                buf.append(Integer.toHexString((data[off + index] & 0xF0) >> 4));
277                buf.append(Integer.toHexString((data[off + index] & 0x0F) >> 0));
278            }
279            // for incomplete lines
280            if (index < 32) {
281                for (int i = index; i < 32; i++) {
282                    if ((i % 8) == 0) {
283                        buf.append(' ');
284                    }
285                    buf.append("  ");
286                }
287            }
288            buf.append("    ");
289            for (index = 0; index < n; index++) {
290                if ((index % 8) == 0) {
291                    buf.append(' ');
292                }
293                int ch = data[off + index] & 0xFF;
294                buf.append(((ch > ' ') && (ch < 127)) ? (char) ch : '.');
295            }
296            buf.append("\n");
297
298            // limit message size
299            if (off + 32 >= 2048) {
300                buf.append("....\n");
301                break;
302            }
303        }
304        return buf.toString();
305    }
306
307}
308