/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * * See the License for the specific language governing permissions and * limitations under the License. */ /** * @author Alexei Y. Zakharov */ package org.apache.harmony.jndi.provider.dns; import java.util.Vector; import java.util.Enumeration; import org.apache.harmony.jndi.internal.nls.Messages; /** * This class represents a domain protocol message. * * @see RFC 1035 */ public class Message { // header section fields /** an ID */ private int id = 0; /** QR; false stands for QUERY request, true for RESPONSE */ private boolean qr = ProviderConstants.QR_QUERY; /** OPCODE; QUERY or IQUERY or STATUS */ private int opCode = 0; /** AA, Authoritative Answer */ private boolean aa = false; /** TC, TrunCation */ private boolean tc = false; /** RD, Recursion Desired */ private boolean rd = false; /** RA, Recursion Available */ private boolean ra = false; /** Z, always should be zero */ // private int z; /** RCODE, Response CODE */ private int rCode = 0; /** QDCOUNT, number of records in question section */ private int qdCount = 0; /** ANCOUNT, number of records in answer section */ private int anCount = 0; /** NSCOUNT, number of records in authority records section */ private int nsCount = 0; /** ARCOUNT, number of records in additional section */ private int arCount = 0; private Vector<QuestionRecord> questionRecords = null; private Vector<ResourceRecord> answerRRs = null; private Vector<ResourceRecord> authorityRRs = null; private Vector<ResourceRecord> additionalRRs = null; /** */ public Message() { questionRecords = new Vector<QuestionRecord>(); answerRRs = new Vector<ResourceRecord>(); authorityRRs = new Vector<ResourceRecord>(); additionalRRs = new Vector<ResourceRecord>(); } /** * Constructs Message object from given parameters * * @param id * ID * @param qr * QR * @param opCode * OPCODE * @param aa * AA * @param tc * TC * @param rd * RA * @param ra * RA * @param rCode * RCODE * @param qdCount * QDCOUNT * @param anCount * ANCOUNT * @param nsCount * NSCOUNT * @param arCount * ARCOUNT */ public Message(int id, boolean qr, int opCode, boolean aa, boolean tc, boolean rd, boolean ra, int rCode, int qdCount, int anCount, int nsCount, int arCount) { this.id = id; this.qr = qr; this.opCode = opCode; this.aa = aa; this.tc = tc; this.rd = rd; this.ra = ra; this.rCode = rCode; this.qdCount = qdCount; this.anCount = anCount; this.nsCount = nsCount; this.arCount = arCount; questionRecords = new Vector<QuestionRecord>(); answerRRs = new Vector<ResourceRecord>(); authorityRRs = new Vector<ResourceRecord>(); additionalRRs = new Vector<ResourceRecord>(); } /** * Generates sequence of bytes that represents the message. * * @param buffer * the buffer to write bytes into * @param startIdx * the index of <code>buffer</code> to start writing at * @return updated index of the <code>buffer</code> * @throws DomainProtocolException * if something went wrong */ public int writeBytes(byte[] buffer, int startIdx) throws DomainProtocolException { int idx = startIdx; int tmp = 0; // basic check if (buffer == null) { // jndi.32=buffer is null throw new DomainProtocolException(Messages.getString("jndi.32")); //$NON-NLS-1$ } // ID idx = ProviderMgr.write16Int(id, buffer, idx); // QR tmp = ProviderMgr.setBit(tmp, ProviderConstants.QR_MASK, qr); // OPCODE tmp &= ~ProviderConstants.OPCODE_MASK; tmp |= (opCode & 0xf) << ProviderConstants.OPCODE_SHIFT; // AA tmp = ProviderMgr.setBit(tmp, ProviderConstants.AA_MASK, aa); // TC tmp = ProviderMgr.setBit(tmp, ProviderConstants.TC_MASK, tc); // RD tmp = ProviderMgr.setBit(tmp, ProviderConstants.RD_MASK, rd); // RA tmp = ProviderMgr.setBit(tmp, ProviderConstants.RA_MASK, ra); // Z, drop all those bits tmp &= ~ProviderConstants.Z_MASK; // RCODE tmp &= ~ProviderConstants.RCODE_MASK; tmp |= (rCode & 0xf) << ProviderConstants.RCODE_SHIFT; // write to buffer idx = ProviderMgr.write16Int(tmp, buffer, idx); // QDCOUNT idx = ProviderMgr.write16Int(qdCount, buffer, idx); // ANCOUNT idx = ProviderMgr.write16Int(anCount, buffer, idx); // NSCOUNT idx = ProviderMgr.write16Int(nsCount, buffer, idx); // ARCOUNT idx = ProviderMgr.write16Int(arCount, buffer, idx); // question section for (int i = 0; i < questionRecords.size(); i++) { QuestionRecord qr = questionRecords.elementAt(i); idx = qr.writeBytes(buffer, idx); } // answer section for (int i = 0; i < answerRRs.size(); i++) { ResourceRecord rr = answerRRs.elementAt(i); idx = rr.writeBytes(buffer, idx); } // authority section for (int i = 0; i < authorityRRs.size(); i++) { ResourceRecord rr = answerRRs.elementAt(i); idx = rr.writeBytes(buffer, idx); } // additional section for (int i = 0; i < additionalRRs.size(); i++) { ResourceRecord rr = answerRRs.elementAt(i); idx = rr.writeBytes(buffer, idx); } return idx; } /** * Parses given sequence of bytes and constructs a message object from it. * * @param mesBytes * the byte array that should be parsed * @param startIdx * an index of <code>mesBytes</code> array to start the parsing * at * @param mes * an object to write a result to, should already be created * @return updated index of <code>mesBytes</code> array * @throws DomainProtocolException * if some error has occurred */ public static int parseMessage(byte[] mesBytes, int startIdx, Message mesObj) throws DomainProtocolException { int idx = startIdx; int tmp, tmp2; int qdCnt; int anCnt; int nsCnt; int arCnt; if (mesObj == null) { // jndi.58=The value of parameter mesObj is null throw new DomainProtocolException(Messages.getString("jndi.58")); //$NON-NLS-1$ } // header section // ID mesObj.setId(ProviderMgr.parse16Int(mesBytes, idx)); idx += 2; // QR & opCode & AA & TC & RD & RA & Z & rCode tmp = ProviderMgr.parse16Int(mesBytes, idx); idx += 2; // QR mesObj.setQR(ProviderMgr.checkBit(tmp, ProviderConstants.QR_MASK)); // OPCODE tmp2 = (tmp & ProviderConstants.OPCODE_MASK) >> ProviderConstants.OPCODE_SHIFT; mesObj.setOpCode(tmp2); // AA mesObj.setAA(ProviderMgr.checkBit(tmp, ProviderConstants.AA_MASK)); // TC mesObj.setTc(ProviderMgr.checkBit(tmp, ProviderConstants.TC_MASK)); // RD mesObj.setRD(ProviderMgr.checkBit(tmp, ProviderConstants.RD_MASK)); // RA mesObj.setRA(ProviderMgr.checkBit(tmp, ProviderConstants.RA_MASK)); // RCODE tmp2 = (tmp & ProviderConstants.RCODE_MASK) >> ProviderConstants.RCODE_SHIFT; mesObj.setRCode(tmp2); // QDCOUNT qdCnt = ProviderMgr.parse16Int(mesBytes, idx); mesObj.setQDCount(qdCnt); idx += 2; // ANCOUNT anCnt = ProviderMgr.parse16Int(mesBytes, idx); mesObj.setANCount(anCnt); idx += 2; // NSCOUNT nsCnt = ProviderMgr.parse16Int(mesBytes, idx); mesObj.setNSCount(nsCnt); idx += 2; // ARCOUNT arCnt = ProviderMgr.parse16Int(mesBytes, idx); mesObj.setARCount(arCnt); idx += 2; // question section for (int i = 0; i < qdCnt; i++) { QuestionRecord qr = new QuestionRecord(); idx = QuestionRecord.parseRecord(mesBytes, idx, qr); mesObj.addQuestionRecord(qr); } // answer section for (int i = 0; i < anCnt; i++) { ResourceRecord rr = new ResourceRecord(); idx = ResourceRecord.parseRecord(mesBytes, idx, rr); mesObj.addAnswerRR(rr); } // authority section for (int i = 0; i < nsCnt; i++) { ResourceRecord rr = new ResourceRecord(); idx = ResourceRecord.parseRecord(mesBytes, idx, rr); mesObj.addAuthorityRR(rr); } // additional section for (int i = 0; i < arCnt; i++) { ResourceRecord rr = new ResourceRecord(); idx = ResourceRecord.parseRecord(mesBytes, idx, rr); mesObj.addAdditionalRR(rr); } return idx; } /** * @return string representation of this message */ @Override @SuppressWarnings("nls") public String toString() { StringBuilder sb = new StringBuilder(); sb.append("ID=" + id + "\n"); if (qr) { sb.append(" QR"); } sb.append(" OPCODE=" + opCode); if (aa) { sb.append(" AA"); } if (tc) { sb.append(" TC"); } if (rd) { sb.append(" RD"); } if (ra) { sb.append(" RA"); } sb.append(" RCODE=" + rCode); sb.append("\n"); sb.append("QDCOUNT=" + qdCount); for (int i = 0; i < questionRecords.size(); i++) { sb.append("\n"); sb.append(questionRecords.elementAt(i).toString()); } sb.append("\n"); sb.append(" ANCOUNT=" + anCount); for (int i = 0; i < answerRRs.size(); i++) { sb.append("\n"); sb.append(answerRRs.elementAt(i).toString()); } sb.append("\n"); sb.append(" NSCOUNT=" + nsCount); for (int i = 0; i < authorityRRs.size(); i++) { sb.append("\n"); sb.append(authorityRRs.elementAt(i).toString()); } sb.append("\n"); sb.append(" ARCOUNT=" + arCount); for (int i = 0; i < additionalRRs.size(); i++) { sb.append("\n"); sb.append(additionalRRs.elementAt(i).toString()); } return sb.toString(); } /** * @return Returns the AA. */ public boolean isAA() { return aa; } /** * @param aa * The AA to set. */ public void setAA(boolean aa) { this.aa = aa; } /** * @return Returns the anCount. */ public int getANCount() { return anCount; } /** * @param anCount * The anCount to set. */ public void setANCount(int anCount) { this.anCount = anCount; } /** * @return Returns the arCount. */ public int getARCount() { return arCount; } /** * @param arCount * The arCount to set. */ public void setARCount(int arCount) { this.arCount = arCount; } /** * @return Returns the id. */ public int getId() { return id; } /** * @param id * The id to set. */ public void setId(int id) { this.id = id; } /** * @return Returns the nsCount. */ public int getNSCount() { return nsCount; } /** * @param nsCount * The nsCount to set. */ public void setNSCount(int nsCount) { this.nsCount = nsCount; } /** * @return Returns the opCode. */ public int getOpCode() { return opCode; } /** * @param opCode * The opCode to set. */ public void setOpCode(int opCode) { this.opCode = opCode; } /** * @return Returns the qdCount. */ public int getQDCount() { return qdCount; } /** * @param qdCount * The qdCount to set. */ public void setQDCount(int qdCount) { this.qdCount = qdCount; } /** * @return Returns the QR. */ public boolean getQR() { return qr; } /** * @param qr * The QR to set. */ public void setQR(boolean qr) { this.qr = qr; } /** * @return Returns the RA. */ public boolean isRA() { return ra; } /** * @param ra * The RA to set. */ public void setRA(boolean ra) { this.ra = ra; } /** * @return Returns the rCode. */ public int getRCode() { return rCode; } /** * @param code * The rCode to set. */ public void setRCode(int code) { rCode = code; } /** * @return Returns the RD. */ public boolean isRD() { return rd; } /** * @param rd * The RD to set. */ public void setRD(boolean rd) { this.rd = rd; } /** * @return Returns the TC. */ public boolean isTc() { return tc; } /** * @param tc * The TC to set. */ public void setTc(boolean tc) { this.tc = tc; } /** * @return question records that are contained by the current message. */ public Enumeration<QuestionRecord> getQuestionRecords() { return questionRecords.elements(); } /** * Adds a new question record to the message. * * @param qr * a record to add */ public void addQuestionRecord(QuestionRecord qr) { questionRecords.addElement(qr); } /** * @return available answer resource records */ public Enumeration<ResourceRecord> getAnswerRRs() { return answerRRs.elements(); } /** * Adds a new question record to the message. * * @param rr * a record to add */ public void addAnswerRR(ResourceRecord rr) { answerRRs.addElement(rr); } /** * @return available authority resource records */ public Enumeration<ResourceRecord> getAuthorityRRs() { return authorityRRs.elements(); } /** * Adds a new question record to the message. * * @param rr * a record to add */ public void addAuthorityRR(ResourceRecord rr) { authorityRRs.addElement(rr); } /** * @return available additional resource records */ public Enumeration<ResourceRecord> getAdditionalRRs() { return additionalRRs.elements(); } /** * Adds a new question record to the message. * * @param rr * a record to add */ public void addAdditionalRR(ResourceRecord rr) { additionalRRs.addElement(rr); } }