Android Open Source - netlib D N S Buffer






From Project

Back to project page netlib.

License

The source code is released under:

Apache License

If you think the Android project netlib listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

/*
 * Copyright 2011 David Simmons/* w ww  .j a va  2 s .c o m*/
 * http://cafbit.com/
 *
 * Licensed 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.
 */

package com.cafbit.netlib.dns;

import java.io.UnsupportedEncodingException;
import java.util.Stack;

/**
 * Encapsulate a byte buffer which maintains its own
 * traversal state and provides several utility methods
 * useful for consuming or producing the binary fields.
 * @author simmons
 */
public class DNSBuffer {
    
    public byte[] bytes;
    public int start;
    public int length;
    public int offset;

    public DNSBuffer(int length) {
        bytes = new byte[length];
        start = 0;
        this.length = length;
        offset = 0;
    }
    
    public DNSBuffer(byte[] bytes) {
        this.bytes = bytes;
        this.start = 0;
        this.length = bytes.length;
        this.offset = 0;
    }
    
    public DNSBuffer(byte[] bytes, int start, int length) {
        this.bytes = bytes;
        this.start = start;
        this.length = length;
        this.offset = start;
    }
    
    //
    
    public void reset() {
        offset = start;
    }
    
    public int remaining() {
        return length - (offset - start);
    }
    
    public void checkRemaining(int needsBytes) {
        if (remaining() < needsBytes) {
            throw new DNSException("insufficient buffer: "+remaining()+" < "+needsBytes);
        }
    }
    
    // read methods
    
    public byte readByte() {
        return bytes[offset++];
    }

    public int readByteAsInt() {
        byte b = bytes[offset++];
        return (int)(b&0xFF);
    }

    public byte[] readBytes(int numBytes) {
        byte[] ba = new byte[numBytes];
        System.arraycopy(bytes, offset, ba, 0, numBytes);
        offset += numBytes;
        return ba;
    }

    public short readShort() {
        byte hi = bytes[offset++];
        byte lo = bytes[offset++];
        return (short)((hi&0xFF)<<8 | (lo&0xFF));
    }

    public int readShortAsInt() {
        byte hi = bytes[offset++];
        byte lo = bytes[offset++];
        return (int)((hi&0xFF)<<8 | (lo&0xFF));
    }
    
    public int readInteger() {
        byte b1 = bytes[offset++];
        byte b2 = bytes[offset++];
        byte b3 = bytes[offset++];
        byte b4 = bytes[offset++];
        return ((b1&0xFF)<<24 | (b2&0xFF)<<16 | (b3&0xFF)<<8 | (b4&0xFF));
    }

    public String readString(int numBytes) {
        String string = bytesToString(bytes, offset, numBytes);
        offset += numBytes;
        return string;
    }
    
    public String readLabel() {
        int length = readByteAsInt();
        byte hiBits = (byte) ((length>>>6) & 0x03);
        if (hiBits == 3) {
            // handle compressed names
            short compressionOffset =
                (short) ((short)((length & 0x3F) << 8) | readByteAsInt());
            pushOffset(start+compressionOffset);
            return readLabel();
        } else if (hiBits > 0) {
            throw new DNSException("unknown label compression format");
        }
        if ((length == 0) && (! offsetStack.isEmpty())) {
            // TODO: it turns out that the compression scheme is not a stack!  clean this up...
            while (! offsetStack.isEmpty()) {
                popOffset();
            }
            return null;
        }
        
        if (length > 63) {
            throw new DNSException("label length > 63");
        } else if (length == 0) {
            return null;
        }
        return readString(length);
    }

    public String readName() {
        StringBuilder sb = new StringBuilder();
        boolean needDot = false;
        String label;
        while ((label = readLabel()) != null) {
            if (needDot) {
                sb.append('.');
            } else {
                needDot = true;
            }
            sb.append(label);
        }
        return sb.toString();
    }
    
    public byte[] readRdata() {
        int length = (int) readShort();
        byte[] rdata = readBytes(length);
        return rdata;
    }
    
    public void rewind(int amount) {
        offset = offset - amount;
    }
    
    // write methods
    
    public void writeByte(byte b) {
        bytes[offset++] = b;
    }
    
    public void writeBytes(byte[] ba) {
        System.arraycopy(ba, 0, bytes, offset, ba.length);
        offset += ba.length;
    }
    
    public void writeShort(short s) {
        bytes[offset++] = (byte)((s>>>8) & 0xFF);
        bytes[offset++] = (byte)(s & 0xFF);
    }

    public void writeInteger(int i) {
        bytes[offset++] = (byte)((i>>>24) & 0xFF);
        bytes[offset++] = (byte)((i>>>16) & 0xFF);
        bytes[offset++] = (byte)((i>>>8) & 0xFF);
        bytes[offset++] = (byte)(i & 0xFF);
    }
    
    public void writeShort(int i) {
        writeShort((short) i);
    }
    
    public void writeString(String string) {
        byte[] stringBytes = stringToBytes(string);
        System.arraycopy(stringBytes, 0, bytes, offset, stringBytes.length);
        offset += stringBytes.length;
    }
    
    public void writeLabel(String label) {
        if (label.length() > 63) {
            throw new DNSException("label length > 63");
        }
        writeByte((byte) lengthInBytes(label));
        writeString(label);
    }
    
    public void writeName(String name) {
        String[] labels = nameToLabels(name);
        for (int i=0; i<labels.length; i++) {
            writeLabel(labels[i]);
        }
        writeByte((byte) 0); // terminating zero length
    }
    
    public void writeRdata(byte[] rdata) {
        writeShort((short) rdata.length);
        writeBytes(rdata);
    }
    
    // public utility methods
    
    public static int nameByteLength(String name) {
        int length = 0;
        for (String label : nameToLabels(name)) {
            length++; // label-length octet
            length += stringToBytes(label).length; // string length in bytes
        }
        return length;
    }

    public static byte[] stringToBytes(String string) {
        byte[] bytes;
        try {
            bytes = string.getBytes("UTF-8");
        } catch (UnsupportedEncodingException e) {
            throw new DNSException(e);
        }
        return bytes;
    }
    
    public static String bytesToString(byte[] bytes, int offset, int length) {
        String string;
        try {
            string = new String(bytes, offset, length, "UTF-8");
        } catch (UnsupportedEncodingException e) {
            throw new DNSException(e);
        }
        return string;
    }
    
    // support for offset stacks, used to parse compressed labels/names.
    
    private Stack<Integer> offsetStack = new Stack<Integer>();
    
    private void pushOffset(int newOffset) {
        offsetStack.push(offset);
        offset = newOffset;
    }
    
    private void popOffset() {
        offset = offsetStack.pop();
    }
    
    // private static utility methods
    
    private static String[] nameToLabels(String name) {
        return name.split("\\.");
    }
    
    // uncomment if needed
    /*
    private static String labelsToName(String[] labels) {
        StringBuilder sb = new StringBuilder();
        for (int i=0; i<labels.length; i++) {
            sb.append(labels[i]);
            if (i != (labels.length-1)) {
                sb.append('.');
            }
        }
        return sb.toString();
    }
    */
    
    private static int lengthInBytes(String string) {
        return stringToBytes(string).length;
    }
    
    public String toString() {
        return String.format("buffer[0x%X]",(offset-start));
    }
}




Java Source Code List

com.cafbit.netlib.AbstractDatagramManagerThread.java
com.cafbit.netlib.Address.java
com.cafbit.netlib.InterfaceInfo.java
com.cafbit.netlib.MDNSPacketEntry.java
com.cafbit.netlib.MDNSReceiverThread.java
com.cafbit.netlib.MulticastReceiverThread.java
com.cafbit.netlib.NetUtil.java
com.cafbit.netlib.NetworkManagerThread.java
com.cafbit.netlib.PacketEntry.java
com.cafbit.netlib.ReceiverThread.java
com.cafbit.netlib.StubPacketEntry.java
com.cafbit.netlib.Util.java
com.cafbit.netlib.dns.DNSAnswer.java
com.cafbit.netlib.dns.DNSBuffer.java
com.cafbit.netlib.dns.DNSComponent.java
com.cafbit.netlib.dns.DNSException.java
com.cafbit.netlib.dns.DNSMessage.java
com.cafbit.netlib.dns.DNSQuestion.java
com.cafbit.netlib.ipc.CommandHandler.java
com.cafbit.netlib.ipc.CommandListener.java
com.cafbit.netlib.ipc.Command.java
com.cafbit.netlib.ipc.DatagramCommand.java
com.cafbit.netlib.ipc.ErrorCommand.java
com.cafbit.netlib.ipc.QuitCommand.java