1 /**
2  *
3  */
4 package javax.jmdns.impl;
5 
6 import java.util.ArrayList;
7 import java.util.Collection;
8 import java.util.Collections;
9 import java.util.LinkedList;
10 import java.util.List;
11 
12 import 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  */
19 public 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      */
DNSMessage(int flags, int id, boolean multicast)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      */
getId()86     public int getId() {
87         return (_multicast ? 0 : _id);
88     }
89 
90     /**
91      * @param id
92      *            the id to set
93      */
setId(int id)94     public void setId(int id) {
95         this._id = id;
96     }
97 
98     /**
99      * @return message flags
100      */
getFlags()101     public int getFlags() {
102         return _flags;
103     }
104 
105     /**
106      * @param flags
107      *            the flags to set
108      */
setFlags(int flags)109     public void setFlags(int flags) {
110         this._flags = flags;
111     }
112 
113     /**
114      * @return true if multicast
115      */
isMulticast()116     public boolean isMulticast() {
117         return _multicast;
118     }
119 
120     /**
121      * @return list of questions
122      */
getQuestions()123     public Collection<? extends DNSQuestion> getQuestions() {
124         return _questions;
125     }
126 
127     /**
128      * @return number of questions in the message
129      */
getNumberOfQuestions()130     public int getNumberOfQuestions() {
131         return this.getQuestions().size();
132     }
133 
getAllAnswers()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      */
getAnswers()145     public Collection<? extends DNSRecord> getAnswers() {
146         return _answers;
147     }
148 
149     /**
150      * @return number of answers in the message
151      */
getNumberOfAnswers()152     public int getNumberOfAnswers() {
153         return this.getAnswers().size();
154     }
155 
156     /**
157      * @return list of authorities
158      */
getAuthorities()159     public Collection<? extends DNSRecord> getAuthorities() {
160         return _authoritativeAnswers;
161     }
162 
163     /**
164      * @return number of authorities in the message
165      */
getNumberOfAuthorities()166     public int getNumberOfAuthorities() {
167         return this.getAuthorities().size();
168     }
169 
170     /**
171      * @return list of additional answers
172      */
getAdditionals()173     public Collection<? extends DNSRecord> getAdditionals() {
174         return _additionals;
175     }
176 
177     /**
178      * @return number of additional in the message
179      */
getNumberOfAdditionals()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      */
isTruncated()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      */
isQuery()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      */
isResponse()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      */
isEmpty()216     public boolean isEmpty() {
217         return (this.getNumberOfQuestions() + this.getNumberOfAnswers() + this.getNumberOfAuthorities() + this.getNumberOfAdditionals()) == 0;
218     }
219 
220     /**
221      * Debugging.
222      */
print()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      */
print(byte[] data)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