/*
* Copyright (c) 2003 University of Murcia. All rights reserved.
* --------------------------------------------------------------
* For more information, please see .
*/
package org.umu.cops.stack;
import org.umu.cops.stack.COPSHeader.Flag;
import org.umu.cops.stack.COPSHeader.OPCode;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
/**
* COPS Keep Alive Message (RFC 2748 pg. 27)
*
* The keep-alive message MUST be transmitted by the PEP within the
* period defined by the minimum of all KA Timer values specified in all
* received CAT messages for the connection. A KA message MUST be
* generated randomly between 1/4 and 3/4 of this minimum KA timer
* interval. When the PDP receives a keep-alive message from a PEP, it
* MUST echo a keep-alive back to the PEP. This message provides
* validation for each side that the connection is still functioning
* even when there is no other messaging.
*
* Note: The client-type in the header MUST always be set to 0 as the KA
* is used for connection verification (not per client session
* verification).
*
* ::=
* []
* Both client and server MAY assume the TCP connection is insufficient
* for the client-type with the minimum time value (specified in the CAT
* message) if no communication activity is detected for a period
* exceeding the timer period. For the PEP, such detection implies the
* remote PDP or connection is down and the PEP SHOULD now attempt to
* use an alternative/backup PDP.
*/
public class COPSKAMsg extends COPSMsg {
// Optional
private final COPSIntegrity _integrity;
/**
* Constructor (generally used for sending messages) which probably should not be used as the PCMM version and
* Flag values on the header are being hardcoded to 1 and UNSOLICITED respectively. Use the next one below instead
* @param integrity - the integrity (optional)
* @throws java.lang.IllegalArgumentException
*/
@Deprecated
public COPSKAMsg(final COPSIntegrity integrity) {
this(new COPSHeader(OPCode.KA, (short)0), integrity);
}
/**
* Constructor (generally used for sending messages).
* @param version - the supported PCMM Version
* @param flag - the flag...
* @param integrity - the integrity (optional)
* @throws java.lang.IllegalArgumentException
*/
public COPSKAMsg(final int version, final Flag flag, final COPSIntegrity integrity) {
this(new COPSHeader(version, flag, OPCode.KA, (short)0), integrity);
}
/**
* Constructor generally used when parsing the bytes of an inbound COPS message but can also be used when the
* COPSHeader information is known.
* @param hdr - COPS Header
* @param integrity - the integrity (optional)
* @throws java.lang.IllegalArgumentException
*/
protected COPSKAMsg(final COPSHeader hdr, final COPSIntegrity integrity) {
super(hdr);
if (!hdr.getOpCode().equals(OPCode.KA))
throw new IllegalArgumentException("OPCode must be of type - " + OPCode.KA);
if (hdr.getClientType() != 0) throw new IllegalArgumentException("Client type must be 0");
_integrity = integrity;
}
// Getter
public COPSIntegrity getIntegrity() {
return (_integrity);
}
@Override
protected void writeBody(final Socket socket) throws IOException {
if (_integrity != null) _integrity.writeData(socket);
}
@Override
protected int getDataLength() {
if (_integrity != null) return _integrity.getDataLength() + _integrity.getHeader().getHdrLength();
else return 0;
}
@Override
protected void dumpBody(final OutputStream os) throws IOException {
if (_integrity != null) _integrity.dump(os);
}
@Override
public boolean equals(final Object o) {
if (this == o) {
return true;
}
if (!(o instanceof COPSKAMsg)) {
return false;
}
if (!super.equals(o)) {
return false;
}
final COPSKAMsg copskaMsg = (COPSKAMsg) o;
return !(_integrity != null ? !_integrity.equals(copskaMsg._integrity) : copskaMsg._integrity != null);
}
@Override
public int hashCode() {
int result = super.hashCode();
result = 31 * result + (_integrity != null ? _integrity.hashCode() : 0);
return result;
}
/**
* Responsible for parsing a byte array to create a COPSDecisionMsg object
* @param hdrData - the object's header data
* @param data - the byte array to parse
* @return - the message object
* @throws COPSException
*/
public static COPSKAMsg parse(final COPSHeaderData hdrData, final byte[] data) throws COPSException {
// Variables for constructor
COPSIntegrity integrity = null;
int dataStart = 0;
while (dataStart < data.length) {
final byte[] buf = new byte[data.length - dataStart];
System.arraycopy(data, dataStart, buf, 0, data.length - dataStart);
final COPSObjHeaderData objHdrData = COPSObjectParser.parseObjHeader(buf);
switch (objHdrData.header.getCNum()) {
case MSG_INTEGRITY:
integrity = COPSIntegrity.parse(objHdrData, buf);
break;
default:
throw new COPSException("Bad Message format, unknown object type");
}
dataStart += objHdrData.msgByteCount;
}
return new COPSKAMsg(hdrData.header, integrity);
}
}