OpenConcerto

Dépôt officiel du code source de l'ERP OpenConcerto
sonarqube

svn://code.openconcerto.org/openconcerto

Rev

Rev 156 | Blame | Compare with Previous | Last modification | View Log | RSS feed

/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 * 
 * Copyright 2011-2019 OpenConcerto, by ILM Informatique. All rights reserved.
 * 
 * The contents of this file are subject to the terms of the GNU General Public License Version 3
 * only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
 * copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
 * language governing permissions and limitations under the License.
 * 
 * When distributing the software, include this License Header Notice in each file.
 */
 
 package org.openconcerto.utils.ntp;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

public final class Message {

    /** Maximum message length (in bytes), without authentication */
    public static final int MAXIMUM_LENGTH = 384;

    /** Leap Indicator. */
    private byte byLeapIndicator;

    /** Version Number. */
    private byte byVersionNumber = 0x04;

    /** Client mode. */
    private byte byMode = 0x03;

    /** Stratum. */
    private byte byStratum;

    /** Poll Interval. */
    private byte byPollInterval;

    /** Precision. */
    private byte byPrecision;

    /** Rood Delay. */
    private double dRootDelay;

    /** Root Dispersion. */
    private double dRootDispersion;

    /** Reference Identifier. */
    private byte[] sReferenceIdentifier = "LOCL".getBytes();

    /** Reference Timestamp. */
    private Timestamp tReferenceTimestamp = Timestamp.ZERO;

    /** Originate Timestamp. */
    private Timestamp tOriginateTimestamp = Timestamp.ZERO;

    /** Receive Timestamp. */
    private Timestamp tReceiveTimestamp = Timestamp.ZERO;

    /** Transmit Timestamp. */
    private Timestamp tTransmitTimestamp = Timestamp.ZERO;

    /**
     * Returns the Leap Indicator.
     * 
     * @return the Leap Indicator.
     */
    public byte getLeapIndicator() {
        return byLeapIndicator;
    }

    /**
     * Sets the Leap Indicator.
     * 
     * @param byLeapIndicator the Leap Indicator.
     */
    public void setLeapIndicator(final byte byLeapIndicator) {
        this.byLeapIndicator = byLeapIndicator;
    }

    /**
     * Returns the Version Number.
     * 
     * @return the Version Number.
     */
    public byte getVersionNumber() {
        return byVersionNumber;
    }

    /**
     * Sets the Version Number.
     * 
     * @param byVersionNumber the Version Number.
     */
    public void setVersionNumber(final byte byVersionNumber) {
        this.byVersionNumber = byVersionNumber;
    }

    /**
     * Returns the Mode.
     * 
     * @return the Mode.
     */
    public byte getMode() {
        return byMode;
    }

    /**
     * Sets the Mode.
     * 
     * @param byMode the Mode.
     */
    public void setMode(final byte byMode) {
        this.byMode = byMode;
    }

    /**
     * Returns the Stratum.
     * 
     * @return the Stratum.
     */
    public byte getStratum() {
        return byStratum;
    }

    /**
     * Sets the Stratum.
     * 
     * @param byStratum the Stratum.
     */
    public void setStratum(final byte byStratum) {
        this.byStratum = byStratum;
    }

    /**
     * Returns the Poll Interval.
     * 
     * @return the Poll Interval.
     */
    public byte getPollInterval() {
        return byPollInterval;
    }

    /**
     * Sets the Poll Interval.
     * 
     * @param byPollInterval the Poll Interval.
     */
    public void setPollInterval(final byte byPollInterval) {
        this.byPollInterval = byPollInterval;
    }

    /**
     * Returns the Precision.
     * 
     * @return the Precision.
     */
    public byte getPrecision() {
        return byPrecision;
    }

    /**
     * Sets the Precision.
     * 
     * @param byPrecision the Precision.
     */
    public void setPrecision(final byte byPrecision) {
        this.byPrecision = byPrecision;
    }

    /**
     * Returns the Root Delay.
     * 
     * @return the Root Delay.
     */
    public double getRootDelay() {
        return dRootDelay;
    }

    /**
     * Sets the Root Delay.
     * 
     * @param dRootDelay the Root Delay.
     */
    public void setRootDelay(final double dRootDelay) {
        this.dRootDelay = dRootDelay;
    }

    /**
     * Returns the Root Dispersion.
     * 
     * @return the Root Dispersion.
     */
    public double getRootDispersion() {
        return dRootDispersion;
    }

    /**
     * Sets the Root Dispersion.
     * 
     * @param dRootDispersion the Root Dispersion.
     */
    public void setRootDispersion(final double dRootDispersion) {
        this.dRootDispersion = dRootDispersion;
    }

    /**
     * Returns the Reference Identifier.
     * 
     * @return the Reference Identifier.
     */
    public byte[] getReferenceIdentifier() {
        return sReferenceIdentifier;
    }

    /**
     * Sets the Reference Identifier.
     * 
     * @param sReferenceIdentifier the Reference Identifier.
     */
    public void setReferenceIdentifier(final byte[] sReferenceIdentifier) {
        this.sReferenceIdentifier = sReferenceIdentifier;
    }

    /**
     * Returns the Reference Timestamp.
     * 
     * @return the Reference Timestamp.
     */
    public Timestamp getReferenceTimestamp() {
        return tReferenceTimestamp;
    }

    /**
     * Sets the Reference Timestamp.
     * 
     * @param tReferenceTimestamp the Reference Timestamp.
     */
    public void setReferenceTimestamp(final Timestamp tReferenceTimestamp) {
        this.tReferenceTimestamp = tReferenceTimestamp;
    }

    /**
     * Returns the Originate Timestamp.
     * 
     * @return the Originate Timestamp.
     */
    public Timestamp getOriginateTimestamp() {
        return tOriginateTimestamp;
    }

    /**
     * Sets the Originate Timestamp.
     * 
     * @param tOriginateTimestamp the Originate Timestamp.
     */
    public void setOriginateTimestamp(final Timestamp tOriginateTimestamp) {
        this.tOriginateTimestamp = tOriginateTimestamp;
    }

    /**
     * Returns the Receive Timestamp.
     * 
     * @return the Receive Timestamp.
     */
    public Timestamp getReceiveTimestamp() {
        return tReceiveTimestamp;
    }

    /**
     * Sets the Receive Timestamp.
     * 
     * @param tReceiveTimestamp the Receive Timestamp.
     */
    public void setReceiveTimestamp(final Timestamp tReceiveTimestamp) {
        this.tReceiveTimestamp = tReceiveTimestamp;
    }

    /**
     * Returns the Transmit Timestamp.
     * 
     * @return the Transmit Timestamp.
     */
    public Timestamp getTransmitTimestamp() {
        return tTransmitTimestamp;
    }

    /**
     * Sets the Transmit Timestamp.
     * 
     * @param tTransmitTimestamp the Transmit Timestamp.
     */
    public void setTransmitTimestamp(final Timestamp tTransmitTimestamp) {
        this.tTransmitTimestamp = tTransmitTimestamp;
    }

    /**
     * Encodes an SNTP message to a byte stream.
     * 
     * @param output the byte stream.
     */
    public void encodeMessage(final OutputStream output) throws IOException {
        byte flags = (byte) (this.getLeapIndicator() << 6);
        flags += (byte) (this.getVersionNumber() << 3);
        flags += this.getMode();
        output.write(flags);
        output.write(this.getStratum());
        output.write(this.getPollInterval());
        output.write(this.getPrecision());
        encodeFixedPoint(this.getRootDelay(), output);
        encodeFixedPoint(this.getRootDispersion(), output);
        encodeBitstring(this.getReferenceIdentifier(), output);
        encodeTimestamp(this.getReferenceTimestamp(), output);
        encodeTimestamp(this.getOriginateTimestamp(), output);
        encodeTimestamp(this.getReceiveTimestamp(), output);
        encodeTimestamp(this.getTransmitTimestamp(), output);
    }

    /**
     * Decodes an SNTP message from a byte stream.
     * 
     * @param input the byte stream.
     * @return the message.
     */
    public static Message decodeMessage(final InputStream input) throws IOException {
        final Message message = new Message();
        final byte flags = (byte) input.read();
        message.setLeapIndicator((byte) (flags >> 6));
        message.setVersionNumber((byte) ((flags >> 3) & 0x07));
        message.setMode((byte) (flags & 0x07));
        message.setStratum((byte) input.read());
        message.setPollInterval((byte) input.read());
        message.setPrecision((byte) input.read());
        message.setRootDelay(decodeFixedPoint(input));
        message.setRootDispersion(decodeFixedPoint(input));
        message.setReferenceIdentifier(decodeBitstring(input));
        message.setReferenceTimestamp(decodeTimestamp(input));
        message.setOriginateTimestamp(decodeTimestamp(input));
        message.setReceiveTimestamp(decodeTimestamp(input));
        message.setTransmitTimestamp(decodeTimestamp(input));

        return message;
    }

    /**
     * Encodes a 32 bit number to a byte stream.
     * 
     * @param number the number to encode.
     * @param output the byte stream.
     * @throws IOException if an error occurs while writting to the stream.
     */
    private static void encode32(final long number, final OutputStream output) throws IOException {
        for (int i = 3; i >= 0; i--) {
            output.write((int) ((number >> (8 * i)) & 0xFF));
        }
    }

    /**
     * Decodes a 32 bit number from a byte stream.
     * 
     * @param input the byte stream.
     * @return the decoded number.
     * @throws IOException if an error occurs while reading from the stream.
     */
    private static long decode32(final InputStream input) throws IOException {
        long number = 0;
        for (int i = 0; i < 4; i++) {
            number = (number << 8) + input.read();
        }
        return number;
    }

    /**
     * Encodes a 32-bit bitstring to a byte stream.
     * 
     * @param bitstring the bitstring to encode.
     * @param output the byte stream.
     * @throws IOException if an error occurs while writting to the stream.
     */
    private static void encodeBitstring(final byte[] bitstring, final OutputStream output) throws IOException {
        final byte[] temp = { 0, 0, 0, 0 };
        System.arraycopy(bitstring, 0, temp, 0, bitstring.length);
        output.write(temp);
    }

    /**
     * Decodes a 32-bit bitstring from a byte stream.
     * 
     * @param input the byte stream.
     * @return the decoded string.
     * @throws IOException if an error occurs while reading from the stream.
     */
    private static byte[] decodeBitstring(final InputStream input) throws IOException {
        final byte[] bitstring = new byte[4];
        input.read(bitstring, 0, 4);

        return bitstring;
    }

    /**
     * Encodes a 32 bit fixed-point number to a byte stream.
     * 
     * @param number the fixed-point number to encode.
     * @param output the byte stream.
     * @throws IOException if an error occurs while writting to the stream.
     */
    private static void encodeFixedPoint(final double number, final OutputStream output) throws IOException {
        encode32((long) (number * 0x10000L), output);
    }

    /**
     * Decodes a 32 bit fixed-point number from a byte stream. The binary point is between bits 15
     * and 16.
     * 
     * @param input the byte stream.
     * @return the decoded fixed-point number.
     * @throws IOException if an error occurs while reading from the stream.
     */
    private static double decodeFixedPoint(final InputStream input) throws IOException {
        return ((double) decode32(input)) / 0x10000L;
    }

    /**
     * Encodes a timestamp to a byte stream.
     * 
     * @param timestamp the timestamp to encode.
     * @param output the byte stream.
     * @throws IOException if an error occurs while writting to the stream.
     */
    private static void encodeTimestamp(final Timestamp timestamp, final OutputStream output) throws IOException {
        encode32(timestamp.getInteger(), output);
        encode32(timestamp.getFraction(), output);
    }

    /**
     * Decodes a timestamp from a byte stream.
     * 
     * @param input the byte stream.
     * @return the decoded timestamp.
     * @throws IOException if an error occurs while reading from the stream.
     */
    private static Timestamp decodeTimestamp(final InputStream input) throws IOException {
        final long integer = decode32(input);
        final long fraction = decode32(input);
        return new Timestamp(integer, fraction);
    }
}