/* * Copyright (c) 2015 Huawei, Inc and others. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/epl-v10.html */ package org.opendaylight.usc.protocol; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.util.Arrays; /** * The USC packet header. */ public class UscHeader { /** * Length of the header by bytes. */ public static final int HEADER_LENGTH = 8; /** * Offset to the payload length field in bytes. */ public static final int PAYLOAD_LENGTH_OFFSET = 6; /** * The length of the payload length field in bytes. */ public static final int PAYLOAD_LENGTH_SIZE = 2; /** * USC protocol version number. */ public static final int USC_VERSION = 1; /** * Types of USC packets. */ public enum OperationType { DATA(1), CONTROL(2), ERROR(3); private final int value; private OperationType(int value) { this.value = value; } public static OperationType valueOf(int v) { return Arrays.stream(values()).filter(value -> value.value == v).findAny().orElse(null); } } private final int uscVersion; private final OperationType operationType; private final int applicationPort; private final int sessionId; private final int payloadLength; /** * Initializes the USC header. * * @param uscVersion * USC version number * @param operationType * USC packet type * @param applicationPort * the port number of the service on the device * @param sessionId * the session ID * @param payloadLength * the length of the payload in bytes */ public UscHeader(int uscVersion, OperationType operationType, int applicationPort, int sessionId, int payloadLength) { super(); this.uscVersion = uscVersion; this.operationType = operationType; this.applicationPort = applicationPort; this.sessionId = sessionId; this.payloadLength = payloadLength; } /** * Set or unset a specific bit in a byte value * * @param value * @param offset * @param target * @return the resulting byte value */ public static byte setBit(byte value, int offset, boolean target) { if (target) { return (byte) (value | (1 << offset)); } else { return (byte) (value & ~(1 << offset)); } } /** * Set or unset a range of bits in a byte value * * @param value * @param offset * @param size * @param target * @return the resulting byte value */ public static byte setBitsAsInteger(byte value, int offset, int size, int target) { int shiftedTarget = (target & ((1 << size) - 1)) << offset; int mask = ~(((1 << size) - 1) << offset); return (byte) (value & mask | shiftedTarget); } /** * Checks whether a bit is set in a byte value * * @param value * @param offset * @return */ public static boolean isBitSet(byte value, int offset) { return ((value >>> offset) & 1) != 0; } /** * Returns a range of bits in a byte value as an integer * * @param value * @param offset * @param size * @return the value of the bits */ public static int getBitsAsInteger(byte value, int offset, int size) { return (value >>> offset) & ((1 << size) - 1); } /** * Constructs an USC header from a byte stream * * @param buf * @return the USC header */ public static UscHeader fromByteBuffer(ByteBuffer buf) { byte byte0 = buf.get(0); // byte 0, bits [0, 4) final int uscVersion = getBitsAsInteger(byte0, 0, 4); // byte 0, bits [4, 8) final OperationType operationType = OperationType.valueOf(getBitsAsInteger(byte0, 4, 4)); // byte 1 reserved // bytes [2, 4) final int applicationPort = buf.getChar(2); // bytes [4, 6) final int sessionId = buf.getChar(4); // bytes [6, 8) final int payloadLength = buf.getChar(PAYLOAD_LENGTH_OFFSET); return new UscHeader(uscVersion, operationType, applicationPort, sessionId, payloadLength); } /** * Constructs an USC header from a byte stream * * @param bytes buffer * @return the USC header */ public static UscHeader getFromBytes(final byte[] bytes) { final ByteBuffer buf = ByteBuffer.wrap(bytes).order(ByteOrder.BIG_ENDIAN); return fromByteBuffer(buf); } /** * Returns the USC version * * @return the USC version */ public int getUscVersion() { return uscVersion; } /** * Returns the USC packet type * * @return the USC packet type */ public OperationType getOperationType() { return operationType; } /** * Returns the port number of the service on the device * * @return the port number of the service on the device */ public int getApplicationPort() { return applicationPort; } /** * Returns the session ID * * @return the session ID */ public int getSessionId() { return sessionId; } /** * Returns the the payload length in bytes * * @return the payload length in bytes */ public int getPayloadLength() { return payloadLength; } /** * Returns the length of the USC header in bytes * * @return the length of the USC header in bytes */ public int length() { return HEADER_LENGTH; } /** * Constructs a byte stream representation of this USC header * * @return the resulting byte stream */ public ByteBuffer toByteBuffer() { byte byte0 = 0; byte0 = setBitsAsInteger(byte0, 0, 4, uscVersion); if (operationType != null) { byte0 = setBitsAsInteger(byte0, 4, 4, operationType.value); } ByteBuffer buf = ByteBuffer.allocate(HEADER_LENGTH).order(ByteOrder.BIG_ENDIAN); buf.put(0, byte0); buf.putChar(2, (char) applicationPort); buf.putChar(4, (char) sessionId); buf.putChar(PAYLOAD_LENGTH_OFFSET, (char) payloadLength); return buf; } }