DNSOutgoing.java
Go to the documentation of this file.
00001 // Copyright 2003-2005 Arthur van Hoff, Rick Blair
00002 // Licensed under Apache License version 2.0
00003 // Original license LGPL
00004 
00005 package javax.jmdns.impl;
00006 
00007 import java.io.ByteArrayOutputStream;
00008 import java.io.IOException;
00009 import java.util.HashMap;
00010 import java.util.Map;
00011 
00012 import javax.jmdns.impl.constants.DNSConstants;
00013 import javax.jmdns.impl.constants.DNSRecordClass;
00014 
00020 public final class DNSOutgoing extends DNSMessage {
00021 
00022     public static class MessageOutputStream extends ByteArrayOutputStream {
00023         private final DNSOutgoing _out;
00024 
00025         private final int         _offset;
00026 
00035         MessageOutputStream(int size, DNSOutgoing out) {
00036             this(size, out, 0);
00037         }
00038 
00039         MessageOutputStream(int size, DNSOutgoing out, int offset) {
00040             super(size);
00041             _out = out;
00042             _offset = offset;
00043         }
00044 
00045         void writeByte(int value) {
00046             this.write(value & 0xFF);
00047         }
00048 
00049         void writeBytes(String str, int off, int len) {
00050             for (int i = 0; i < len; i++) {
00051                 writeByte(str.charAt(off + i));
00052             }
00053         }
00054 
00055         void writeBytes(byte data[]) {
00056             if (data != null) {
00057                 writeBytes(data, 0, data.length);
00058             }
00059         }
00060 
00061         void writeBytes(byte data[], int off, int len) {
00062             for (int i = 0; i < len; i++) {
00063                 writeByte(data[off + i]);
00064             }
00065         }
00066 
00067         void writeShort(int value) {
00068             writeByte(value >> 8);
00069             writeByte(value);
00070         }
00071 
00072         void writeInt(int value) {
00073             writeShort(value >> 16);
00074             writeShort(value);
00075         }
00076 
00077         void writeUTF(String str, int off, int len) {
00078             // compute utf length
00079             int utflen = 0;
00080             for (int i = 0; i < len; i++) {
00081                 int ch = str.charAt(off + i);
00082                 if ((ch >= 0x0001) && (ch <= 0x007F)) {
00083                     utflen += 1;
00084                 } else {
00085                     if (ch > 0x07FF) {
00086                         utflen += 3;
00087                     } else {
00088                         utflen += 2;
00089                     }
00090                 }
00091             }
00092             // write utf length
00093             writeByte(utflen);
00094             // write utf data
00095             for (int i = 0; i < len; i++) {
00096                 int ch = str.charAt(off + i);
00097                 if ((ch >= 0x0001) && (ch <= 0x007F)) {
00098                     writeByte(ch);
00099                 } else {
00100                     if (ch > 0x07FF) {
00101                         writeByte(0xE0 | ((ch >> 12) & 0x0F));
00102                         writeByte(0x80 | ((ch >> 6) & 0x3F));
00103                         writeByte(0x80 | ((ch >> 0) & 0x3F));
00104                     } else {
00105                         writeByte(0xC0 | ((ch >> 6) & 0x1F));
00106                         writeByte(0x80 | ((ch >> 0) & 0x3F));
00107                     }
00108                 }
00109             }
00110         }
00111 
00112         void writeName(String name) {
00113             writeName(name, true);
00114         }
00115 
00116         void writeName(String name, boolean useCompression) {
00117             String aName = name;
00118             while (true) {
00119                 int n = aName.indexOf('.');
00120                 if (n < 0) {
00121                     n = aName.length();
00122                 }
00123                 if (n <= 0) {
00124                     writeByte(0);
00125                     return;
00126                 }
00127                 String label = aName.substring(0, n);
00128                 if (useCompression && USE_DOMAIN_NAME_COMPRESSION) {
00129                     Integer offset = _out._names.get(aName);
00130                     if (offset != null) {
00131                         int val = offset.intValue();
00132                         writeByte((val >> 8) | 0xC0);
00133                         writeByte(val & 0xFF);
00134                         return;
00135                     }
00136                     _out._names.put(aName, Integer.valueOf(this.size() + _offset));
00137                     writeUTF(label, 0, label.length());
00138                 } else {
00139                     writeUTF(label, 0, label.length());
00140                 }
00141                 aName = aName.substring(n);
00142                 if (aName.startsWith(".")) {
00143                     aName = aName.substring(1);
00144                 }
00145             }
00146         }
00147 
00148         void writeQuestion(DNSQuestion question) {
00149             writeName(question.getName());
00150             writeShort(question.getRecordType().indexValue());
00151             writeShort(question.getRecordClass().indexValue());
00152         }
00153 
00154         void writeRecord(DNSRecord rec, long now) {
00155             writeName(rec.getName());
00156             writeShort(rec.getRecordType().indexValue());
00157             writeShort(rec.getRecordClass().indexValue() | ((rec.isUnique() && _out.isMulticast()) ? DNSRecordClass.CLASS_UNIQUE : 0));
00158             writeInt((now == 0) ? rec.getTTL() : rec.getRemainingTTL(now));
00159 
00160             // We need to take into account the 2 size bytes
00161             MessageOutputStream record = new MessageOutputStream(512, _out, _offset + this.size() + 2);
00162             rec.write(record);
00163             byte[] byteArray = record.toByteArray();
00164 
00165             writeShort(byteArray.length);
00166             write(byteArray, 0, byteArray.length);
00167         }
00168 
00169     }
00170 
00174     public static boolean             USE_DOMAIN_NAME_COMPRESSION = true;
00175 
00176     Map<String, Integer>              _names;
00177 
00178     private int                       _maxUDPPayload;
00179 
00180     private final MessageOutputStream _questionsBytes;
00181 
00182     private final MessageOutputStream _answersBytes;
00183 
00184     private final MessageOutputStream _authoritativeAnswersBytes;
00185 
00186     private final MessageOutputStream _additionalsAnswersBytes;
00187 
00188     private final static int          HEADER_SIZE                 = 12;
00189 
00195     public DNSOutgoing(int flags) {
00196         this(flags, true, DNSConstants.MAX_MSG_TYPICAL);
00197     }
00198 
00205     public DNSOutgoing(int flags, boolean multicast) {
00206         this(flags, multicast, DNSConstants.MAX_MSG_TYPICAL);
00207     }
00208 
00217     public DNSOutgoing(int flags, boolean multicast, int senderUDPPayload) {
00218         super(flags, 0, multicast);
00219         _names = new HashMap<String, Integer>();
00220         _maxUDPPayload = (senderUDPPayload > 0 ? senderUDPPayload : DNSConstants.MAX_MSG_TYPICAL);
00221         _questionsBytes = new MessageOutputStream(senderUDPPayload, this);
00222         _answersBytes = new MessageOutputStream(senderUDPPayload, this);
00223         _authoritativeAnswersBytes = new MessageOutputStream(senderUDPPayload, this);
00224         _additionalsAnswersBytes = new MessageOutputStream(senderUDPPayload, this);
00225     }
00226 
00232     public int availableSpace() {
00233         return _maxUDPPayload - HEADER_SIZE - _questionsBytes.size() - _answersBytes.size() - _authoritativeAnswersBytes.size() - _additionalsAnswersBytes.size();
00234     }
00235 
00242     public void addQuestion(DNSQuestion rec) throws IOException {
00243         MessageOutputStream record = new MessageOutputStream(512, this);
00244         record.writeQuestion(rec);
00245         byte[] byteArray = record.toByteArray();
00246         if (byteArray.length < this.availableSpace()) {
00247             _questions.add(rec);
00248             _questionsBytes.write(byteArray, 0, byteArray.length);
00249         } else {
00250             throw new IOException("message full");
00251         }
00252     }
00253 
00261     public void addAnswer(DNSIncoming in, DNSRecord rec) throws IOException {
00262         if ((in == null) || !rec.suppressedBy(in)) {
00263             this.addAnswer(rec, 0);
00264         }
00265     }
00266 
00274     public void addAnswer(DNSRecord rec, long now) throws IOException {
00275         if (rec != null) {
00276             if ((now == 0) || !rec.isExpired(now)) {
00277                 MessageOutputStream record = new MessageOutputStream(512, this);
00278                 record.writeRecord(rec, now);
00279                 byte[] byteArray = record.toByteArray();
00280                 if (byteArray.length < this.availableSpace()) {
00281                     _answers.add(rec);
00282                     _answersBytes.write(byteArray, 0, byteArray.length);
00283                 } else {
00284                     throw new IOException("message full");
00285                 }
00286             }
00287         }
00288     }
00289 
00296     public void addAuthorativeAnswer(DNSRecord rec) throws IOException {
00297         MessageOutputStream record = new MessageOutputStream(512, this);
00298         record.writeRecord(rec, 0);
00299         byte[] byteArray = record.toByteArray();
00300         if (byteArray.length < this.availableSpace()) {
00301             _authoritativeAnswers.add(rec);
00302             _authoritativeAnswersBytes.write(byteArray, 0, byteArray.length);
00303         } else {
00304             throw new IOException("message full");
00305         }
00306     }
00307 
00315     public void addAdditionalAnswer(DNSIncoming in, DNSRecord rec) throws IOException {
00316         MessageOutputStream record = new MessageOutputStream(512, this);
00317         record.writeRecord(rec, 0);
00318         byte[] byteArray = record.toByteArray();
00319         if (byteArray.length < this.availableSpace()) {
00320             _additionals.add(rec);
00321             _additionalsAnswersBytes.write(byteArray, 0, byteArray.length);
00322         } else {
00323             throw new IOException("message full");
00324         }
00325     }
00326 
00332     public byte[] data() {
00333         long now = System.currentTimeMillis(); // System.currentTimeMillis()
00334         _names.clear();
00335 
00336         MessageOutputStream message = new MessageOutputStream(_maxUDPPayload, this);
00337         message.writeShort(_multicast ? 0 : this.getId());
00338         message.writeShort(this.getFlags());
00339         message.writeShort(this.getNumberOfQuestions());
00340         message.writeShort(this.getNumberOfAnswers());
00341         message.writeShort(this.getNumberOfAuthorities());
00342         message.writeShort(this.getNumberOfAdditionals());
00343         for (DNSQuestion question : _questions) {
00344             message.writeQuestion(question);
00345         }
00346         for (DNSRecord record : _answers) {
00347             message.writeRecord(record, now);
00348         }
00349         for (DNSRecord record : _authoritativeAnswers) {
00350             message.writeRecord(record, now);
00351         }
00352         for (DNSRecord record : _additionals) {
00353             message.writeRecord(record, now);
00354         }
00355         return message.toByteArray();
00356     }
00357 
00358     @Override
00359     public boolean isQuery() {
00360         return (this.getFlags() & DNSConstants.FLAGS_QR_MASK) == DNSConstants.FLAGS_QR_QUERY;
00361     }
00362 
00366     String print(boolean dump) {
00367         StringBuilder buf = new StringBuilder();
00368         buf.append(this.print());
00369         if (dump) {
00370             buf.append(this.print(this.data()));
00371         }
00372         return buf.toString();
00373     }
00374 
00375     @Override
00376     public String toString() {
00377         StringBuffer buf = new StringBuffer();
00378         buf.append(isQuery() ? "dns[query:" : "dns[response:");
00379         buf.append(" id=0x");
00380         buf.append(Integer.toHexString(this.getId()));
00381         if (this.getFlags() != 0) {
00382             buf.append(", flags=0x");
00383             buf.append(Integer.toHexString(this.getFlags()));
00384             if ((this.getFlags() & DNSConstants.FLAGS_QR_RESPONSE) != 0) {
00385                 buf.append(":r");
00386             }
00387             if ((this.getFlags() & DNSConstants.FLAGS_AA) != 0) {
00388                 buf.append(":aa");
00389             }
00390             if ((this.getFlags() & DNSConstants.FLAGS_TC) != 0) {
00391                 buf.append(":tc");
00392             }
00393         }
00394         if (this.getNumberOfQuestions() > 0) {
00395             buf.append(", questions=");
00396             buf.append(this.getNumberOfQuestions());
00397         }
00398         if (this.getNumberOfAnswers() > 0) {
00399             buf.append(", answers=");
00400             buf.append(this.getNumberOfAnswers());
00401         }
00402         if (this.getNumberOfAuthorities() > 0) {
00403             buf.append(", authorities=");
00404             buf.append(this.getNumberOfAuthorities());
00405         }
00406         if (this.getNumberOfAdditionals() > 0) {
00407             buf.append(", additionals=");
00408             buf.append(this.getNumberOfAdditionals());
00409         }
00410         if (this.getNumberOfQuestions() > 0) {
00411             buf.append("\nquestions:");
00412             for (DNSQuestion question : _questions) {
00413                 buf.append("\n\t");
00414                 buf.append(question);
00415             }
00416         }
00417         if (this.getNumberOfAnswers() > 0) {
00418             buf.append("\nanswers:");
00419             for (DNSRecord record : _answers) {
00420                 buf.append("\n\t");
00421                 buf.append(record);
00422             }
00423         }
00424         if (this.getNumberOfAuthorities() > 0) {
00425             buf.append("\nauthorities:");
00426             for (DNSRecord record : _authoritativeAnswers) {
00427                 buf.append("\n\t");
00428                 buf.append(record);
00429             }
00430         }
00431         if (this.getNumberOfAdditionals() > 0) {
00432             buf.append("\nadditionals:");
00433             for (DNSRecord record : _additionals) {
00434                 buf.append("\n\t");
00435                 buf.append(record);
00436             }
00437         }
00438         buf.append("\nnames=");
00439         buf.append(_names);
00440         buf.append("]");
00441         return buf.toString();
00442     }
00443 
00447     public int getMaxUDPPayload() {
00448         return this._maxUDPPayload;
00449     }
00450 
00451 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Friends


zeroconf_jmdns
Author(s): Daniel Stonier
autogenerated on Tue Nov 6 2012 13:08:26