/*
* Copyright 2009-2014 Jagornet Technologies, LLC. All Rights Reserved.
*
* This software is the proprietary information of Jagornet Technologies, LLC.
* Use is subject to license terms.
*
*/
/*
* This file DhcpV6RelayMessage.java is part of Jagornet DHCP.
*
* Jagornet DHCP is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Jagornet DHCP is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Jagornet DHCP. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.jagornet.dhcp.message;
import java.io.IOException;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.jagornet.dhcp.option.base.DhcpOption;
import com.jagornet.dhcp.option.v6.DhcpV6RelayOption;
import com.jagornet.dhcp.util.DhcpConstants;
import com.jagornet.dhcp.util.Util;
/**
* Title: DhcpV6RelayMessage
* Description:Object that represents a DHCPv6 relay message as defined in
* RFC 3315.
*
* There are two relay agent messages, which share the following format:
*
* <pre>
* 0 1 2 3
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | msg-type | hop-count | |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
* | |
* | link-address |
* | |
* | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-|
* | | |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
* | |
* | peer-address |
* | |
* | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-|
* | | |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
* . .
* . options (variable number and length) .... .
* | |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*
* The following sections describe the use of the Relay Agent message
* header.
*
* 7.1. Relay-forward Message
*
* The following table defines the use of message fields in a Relay-
* forward message.
*
* msg-type RELAY-FORW
*
* hop-count Number of relay agents that have relayed this
* message.
*
* link-address A global or site-local address that will be used by
* the server to identify the link on which the client
* is located.
*
* peer-address The address of the client or relay agent from which
* the message to be relayed was received.
*
* options MUST include a "Relay Message option" (see
* section 22.10); MAY include other options added by
* the relay agent.
*
* 7.2. Relay-reply Message
*
* The following table defines the use of message fields in a
* Relay-reply message.
*
* msg-type RELAY-REPL
*
* hop-count Copied from the Relay-forward message
*
* link-address Copied from the Relay-forward message
*
* peer-address Copied from the Relay-forward message
*
* options MUST include a "Relay Message option"; see
* section 22.10; MAY include other options
* </pre>
*
* @author A. Gregory Rabil
*/
public class DhcpV6RelayMessage extends DhcpV6Message
{
private static Logger log = LoggerFactory.getLogger(DhcpV6RelayMessage.class);
// messageType is in DhcpMessage superclass
/** The hop count. Need a short to hold unsigned byte. */
protected short hopCount = 0;
/** The link address. A global or site-local address that will be used by
* the server to identify the link on which the client is located. */
protected InetAddress linkAddress = null;
/** The peer address. The address of the client or relay agent from which
* the message to be relayed was received. */
protected InetAddress peerAddress = null;
/** The relay option. MUST have a relay option to be a relay message.
* this object is here as a convenience, because
* it must ALSO be in the dhcpOptions Map that is
* in the DhcpMessage superclass */
protected DhcpV6RelayOption relayOption = null;
/**
* Construct a DhcpRelayMessage.
*
* @param localAddress InetSocketAddress on the local host on which
* this message is received or sent
* @param remoteAddress InetSocketAddress on the remote host on which
* this message is sent or received
*/
public DhcpV6RelayMessage(InetSocketAddress localAddress, InetSocketAddress remoteAddress)
{
super(localAddress, remoteAddress);
}
/* (non-Javadoc)
* @see com.jagornet.dhcpv6.message.DhcpMessage#encode()
*/
@Override
public ByteBuffer encode() throws IOException
{
if (log.isDebugEnabled())
log.debug("Encoding DhcpRelayMessage for: " + remoteAddress);
ByteBuffer buf = ByteBuffer.allocate(1024);
buf.put((byte)messageType);
buf.put((byte)hopCount);
buf.put(linkAddress.getAddress());
buf.put(peerAddress.getAddress());
buf.put(encodeOptions());
buf.flip();
if (log.isDebugEnabled())
log.debug("DhcpRelayMessage encoded.");
return buf;
}
/* (non-Javadoc)
* @see com.jagornet.dhcpv6.message.DhcpMessage#decode(java.nio.ByteBuffer)
*/
@Override
public void decode(ByteBuffer buf) throws IOException
{
if (log.isDebugEnabled())
log.debug("Decoding DhcpRelayMessage from: " + remoteAddress);
if ((buf != null) && buf.hasRemaining()) {
decodeMessageType(buf);
setHopCount(Util.getUnsignedByte(buf));
if (log.isDebugEnabled())
log.debug("HopCount=" + getHopCount());
if (buf.hasRemaining()) {
InetAddress linkAddr = decodeInet6Address(buf);
setLinkAddress(linkAddr);
if (log.isDebugEnabled())
log.debug("LinkAddress: " + linkAddr);
if (buf.hasRemaining()) {
InetAddress peerAddr = decodeInet6Address(buf);
setPeerAddress(peerAddr);
if (log.isDebugEnabled())
log.debug("PeerAddress: " + peerAddr);
if (buf.hasRemaining()) {
Map<Integer,DhcpOption> options = decodeOptions(buf);
DhcpOption dhcpOption = options.get(DhcpConstants.V6OPTION_RELAY_MSG);
if ((dhcpOption != null) && (dhcpOption instanceof DhcpV6RelayOption)) {
relayOption = (DhcpV6RelayOption) dhcpOption;
setDhcpOptionMap(options);
}
else {
String errmsg = "Failed to decode relay message: no relay option found";
log.error(errmsg);
throw new IOException(errmsg);
}
}
else {
String errmsg = "Failed to decode options: buffer is empty";
log.error(errmsg);
throw new IOException(errmsg);
}
}
else {
String errmsg = "Failed to decode peer address: buffer is empty";
log.error(errmsg);
throw new IOException(errmsg);
}
}
else {
String errmsg = "Failed to decode link address: buffer is empty";
log.error(errmsg);
throw new IOException(errmsg);
}
}
else {
String errmsg = "Failed to decode hop count: buffer is empty";
log.error(errmsg);
throw new IOException(errmsg);
}
if (log.isDebugEnabled()) {
log.debug("DhcpRelayMessage decoded.");
}
}
/**
* Decode inet6 address.
*
* @param iobuf the iobuf
*
* @return the inet address
*
* @throws IOException Signals that an I/O exception has occurred.
*/
protected InetAddress decodeInet6Address(ByteBuffer buf) throws IOException
{
if (buf.remaining() >= 16) {
byte[] addr = new byte[16];
buf.get(addr);
return Inet6Address.getByAddress(addr);
}
else {
String errmsg = "Failed to decode address: " + buf.remaining() +
" bytes remaining in buffer.";
log.error(errmsg);
throw new IOException(errmsg);
}
}
/* (non-Javadoc)
* @see com.jagornet.dhcpv6.message.DhcpMessage#getLength()
*/
@Override
public int getLength()
{
int len = 34; // relay msg type (1) + hop count (1) +
// link addr (16) + peer addr (16)
len += getOptionsLength();
return len;
}
/**
* Gets the hop count.
*
* @return the hop count
*/
public short getHopCount()
{
return hopCount;
}
/**
* Sets the hop count.
*
* @param hopCount the new hop count
*/
public void setHopCount(short hopCount)
{
this.hopCount = hopCount;
}
/**
* Gets the link address.
*
* @return the link address
*/
public InetAddress getLinkAddress()
{
return linkAddress;
}
/**
* Sets the link address.
*
* @param linkAddress the new link address
*/
public void setLinkAddress(InetAddress linkAddress)
{
this.linkAddress = linkAddress;
}
/**
* Gets the peer address.
*
* @return the peer address
*/
public InetAddress getPeerAddress()
{
return peerAddress;
}
/**
* Sets the peer address.
*
* @param peerAddress the new peer address
*/
public void setPeerAddress(InetAddress peerAddress)
{
this.peerAddress = peerAddress;
}
/**
* Gets the relay option.
*
* @return the relay option
*/
public DhcpV6RelayOption getRelayOption()
{
return relayOption;
}
/**
* Sets the relay option.
*
* @param relayOption the new relay option
*/
public void setRelayOption(DhcpV6RelayOption relayOption)
{
this.relayOption = relayOption;
}
}