All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.addc.commons.slp.messages.SLPMessageHeader Maven / Gradle / Ivy

Go to download

The addc-slp library supplies client classes for registering objects with a Service Location Protocol Daemon and for looking theses objects up later.

There is a newer version: 2.6
Show newest version
package com.addc.commons.slp.messages;

import java.io.DataInputStream;
import java.io.DataOutput;
import java.io.IOException;
import java.util.Locale;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.addc.commons.slp.SLPConstants;
import com.addc.commons.slp.ServiceLocationException;

/**
 * The SLPMessageHeader abstracts the SLP message header information.
 */
public class SLPMessageHeader {
    private static final Logger LOGGER= LoggerFactory.getLogger(SLPMessageHeader.class);
    private static final int OVERFLOW= 0x80;
    private static final int FRESH= 0x40;
    private static final int MCAST= 0x20;

    private int version;
    private int functionId;
    private int xid;
    private boolean fresh;
    private boolean multicast;
    private boolean overflow;
    private int size;
    private Locale locale;
    private boolean tcp;
    private final int mtu;

    /**
     * Create a new SLPMessageHeader for reading from data input stream
     * 
     * @param mtu
     *            The MTU size
     */
    public SLPMessageHeader(int mtu) {
        this.mtu= mtu;
    }

    /**
     * Create a new SLPMessageHeader.
     * 
     * @param version
     *            the version number (1 or 2).
     * @param functionId
     *            The function ID.
     * @param xid
     *            The XID.
     * @param size
     *            The size of the message
     * @param fresh
     *            true if the request is fresh.
     * @param multicast
     *            true if the request is multicast.
     * @param locale
     *            The locale to use
     * @param tcp
     *            true if connection is over TCP
     * @param mtu
     *            The MTU size
     */
    public SLPMessageHeader(int version, int functionId, int xid, int size, boolean fresh, boolean multicast,
            Locale locale, boolean tcp, int mtu) {
        this.version= version;
        this.functionId= functionId;
        this.xid= xid;
        this.fresh= fresh;
        this.multicast= multicast;
        this.size= size;
        this.locale= locale;
        this.mtu= mtu;
        this.tcp= tcp;
    }

    /**
     * Get the version
     * 
     * @return the version
     */
    public int getVersion() {
        return version;
    }

    /**
     * Set the version (for testing only)
     * 
     * @param version
     *            the version to set
     */
    void setVersion(int version) {
        this.version= version;
    }

    /**
     * Get the functionId
     * 
     * @return the functionId
     */
    public int getFunctionId() {
        return functionId;
    }

    /**
     * Get the xid
     * 
     * @return the xid
     */
    public int getXid() {
        return xid;
    }

    /**
     * Get the fresh
     * 
     * @return the fresh
     */
    public boolean isFresh() {
        return fresh;
    }

    /**
     * Get the multicast
     * 
     * @return the multicast
     */
    public boolean isMulticast() {
        return multicast;
    }

    /**
     * Get the overflow
     * 
     * @return the overflow
     */
    public boolean isOverflow() {
        return overflow;
    }

    /**
     * Get the size
     * 
     * @return the size
     */
    public int getSize() {
        return size;
    }

    /**
     * Get the Locale
     * 
     * @return the Locale
     */
    public Locale getLocale() {
        return locale;
    }

    /**
     * Get the tcp
     * 
     * @return the tcp
     */
    public boolean isTcp() {
        return tcp;
    }

    /**
     * Get the mtu
     * 
     * @return the mtu
     */
    public int getMTU() {
        return mtu;
    }

    /**
     * Write the Message Header to the given output stream
     *
     * @param dos
     *            The data output to write to
     * @throws IOException
     *             If there was an error writing to the output
     */
    public void write(DataOutput dos) throws IOException {
        int flags= 0;
        if (functionId == SLPConstants.SRVREG) {
            flags|= FRESH;
        }
        if (multicast) {
            flags|= MCAST;
        }
        if (!tcp && size > mtu) {
            flags|= OVERFLOW;
        }

        dos.writeByte(version);
        // Function id (1)
        dos.writeByte(functionId);
        // length (2 - 4)
        dos.write((byte) (size >> 16));
        dos.write((byte) ((size >> 8) & 0xFF));
        dos.write((byte) (size & 0xFF));
        // flags (5)
        dos.writeByte(flags);
        // reserved and extensions (6-9)
        dos.writeByte(0);
        dos.writeByte(0);
        dos.writeByte(0);
        dos.writeByte(0);
        // xid (10 - 11)
        dos.writeShort(xid);
        dos.writeUTF(locale.getLanguage());
    }

    /**
     * Read the fields of the header from the given input
     *
     * @param dis
     *            The data input to read from
     * @throws IOException
     *             If there was an I/O error
     * @throws ServiceLocationException
     *             If the header has version 1
     */
    public void read(DataInputStream dis) throws IOException, ServiceLocationException {
        version= dis.readByte();
        if (1 == version) {
            dis.readByte(); // funcID
            int length= dis.readShort();
            byte[] drop= new byte[length - 4];
            dis.readFully(drop);
            LOGGER.warn("Dropped SLPv1 message");
            throw new ServiceLocationException("Invalid SLP version " + version, SLPConstants.PARSE_ERROR);
        }
        functionId= dis.readByte();
        size= readInt(dis, 3);
        int flags= dis.readByte();
        if (!tcp && (flags & OVERFLOW) != 0) {
            throw new IOException("Not tcp and everflow flag set, cannot read");
        }

        overflow= (flags & OVERFLOW) == OVERFLOW;
        multicast= (flags & MCAST) == MCAST;
        fresh= (flags & FRESH) == FRESH;
        dis.readByte();
        dis.readByte();
        dis.readByte();
        dis.readByte();
        xid= dis.readShort();
        locale= new Locale(dis.readUTF(), "");
    }

    /**
     * parse a numerical value that can be spanned over multiple bytes.
     * 
     * @param input
     *            the data input stream.
     * @param len
     *            the number of bytes to read.
     * @return the int value.
     * @throws IOException
     *             in case of IO errors.
     */
    private int readInt(final DataInputStream input, final int len) throws IOException {
        int value= 0;
        for (int i= 0; i < len; i++) {
            value<<= 8;
            value+= input.readByte() & 0xff;
        }
        return value;
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy