
com.guardtime.ksi.service.tcp.KSITCPTransaction Maven / Gradle / Ivy
/*
* Copyright 2013-2018 Guardtime, Inc.
*
* This file is part of the Guardtime client SDK.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES, CONDITIONS, OR OTHER LICENSES OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
* "Guardtime" and "KSI" are trademarks or registered trademarks of
* Guardtime, Inc., and no license to trademarks is granted; Guardtime
* reserves and retains all trademark rights.
*
*/
package com.guardtime.ksi.service.tcp;
import com.guardtime.ksi.exceptions.KSIException;
import com.guardtime.ksi.service.KSIProtocolException;
import com.guardtime.ksi.tlv.GlobalTlvTypes;
import com.guardtime.ksi.tlv.MultipleTLVElementException;
import com.guardtime.ksi.tlv.TLVElement;
import com.guardtime.ksi.tlv.TLVParserException;
import com.guardtime.ksi.util.Util;
import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.core.future.WriteFuture;
import org.apache.mina.core.session.IoSession;
import java.io.IOException;
import java.io.InputStream;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.TimeUnit;
/**
* Represents a single TCP transaction.
*/
class KSITCPTransaction {
private static final int REQUEST_WRAPPER_TAG = 0x201;
private static final int RESPONSE_WRAPPER_TAG = 0x202;
private static final int REQ_ID_TAG = 0x1;
private static final int PDU_V2_PAYLOAD_ELEMENT_TAG = 0x02;
private final BlockingQueue availableResponse = new ArrayBlockingQueue<>(1);
private long correlationId;
private TLVElement request;
private TLVElement response;
private static final Object CONF_REQUEST_LOCK = new Object();
private static Long confRequestId = 0L;
private KSITCPTransaction() {
}
static KSITCPTransaction fromRequest(InputStream request) throws IOException, KSIException {
KSITCPTransaction transaction = new KSITCPTransaction();
TLVElement tlv = TLVElement.create(Util.toByteArray(request));
transaction.correlationId = isConfigurationPayload(tlv) ? getNewConfId() : extractTransactionIdFromRequestTLV(tlv);
transaction.request = tlv;
return transaction;
}
static KSITCPTransaction fromResponse(IoBuffer ioBuffer) throws KSIException {
KSITCPTransaction transaction = new KSITCPTransaction();
byte[] responseData = new byte[ioBuffer.remaining()];
ioBuffer.get(responseData);
TLVElement tlv = parse(responseData);
if (isConfigurationPayload(tlv)) {
synchronized (CONF_REQUEST_LOCK) {
transaction.correlationId = confRequestId;
confRequestId = confRequestId + 1;
}
} else {
transaction.correlationId = extractTransactionIdFromResponseTLV(tlv);
}
transaction.response = tlv;
return transaction;
}
private static long getNewConfId() {
synchronized (CONF_REQUEST_LOCK) {
return --confRequestId;
}
}
private static TLVElement parse(byte[] data) throws KSIProtocolException {
try {
return TLVElement.create(data);
} catch (MultipleTLVElementException e) {
throw new KSIProtocolException("Invalid KSI response. Response message contains multiple TLV elements", e);
} catch (TLVParserException e) {
throw new KSIProtocolException("Can't parse response message", e);
}
}
private static boolean isConfigurationPayload(TLVElement tlv) {
if (tlv.getType() == GlobalTlvTypes.ELEMENT_TYPE_AGGREGATION_REQUEST_PDU_V2 ||
tlv.getType() == GlobalTlvTypes.ELEMENT_TYPE_AGGREGATION_RESPONSE_PDU_V2) {
return tlv.getFirstChildElement(0x04) != null;
}
return false;
}
private static long extractTransactionIdFromRequestTLV(TLVElement tlvData) throws KSITCPTransactionException {
try {
if (tlvData.getType() == GlobalTlvTypes.ELEMENT_TYPE_AGGREGATION_REQUEST_PDU_V2
|| tlvData.getType() == GlobalTlvTypes.ELEMENT_TYPE_EXTENSION_REQUEST_PDU_V2) {
return extractRequestId(tlvData, PDU_V2_PAYLOAD_ELEMENT_TAG);
}
return extractRequestId(tlvData, REQUEST_WRAPPER_TAG);
} catch (Exception e) {
throw new KSITCPTransactionException("Request TLV was corrupt. Could not parse request ID.", e);
}
}
private static long extractTransactionIdFromResponseTLV(TLVElement tlvData) throws KSITCPTransactionException {
try {
if (tlvData.getType() == GlobalTlvTypes.ELEMENT_TYPE_AGGREGATION_RESPONSE_PDU_V2
|| tlvData.getType() == GlobalTlvTypes.ELEMENT_TYPE_EXTENSION_RESPONSE_PDU_V2) {
return extractRequestId(tlvData, PDU_V2_PAYLOAD_ELEMENT_TAG);
}
return extractRequestId(tlvData, RESPONSE_WRAPPER_TAG);
} catch (Exception e) {
throw new KSITCPTransactionException("Response TLV was corrupt. Could not parse request ID.", e);
}
}
private static long extractRequestId(TLVElement tlvData, int outerLayerTagName) throws TLVParserException {
TLVElement payloadElementTag = tlvData.getFirstChildElement(outerLayerTagName);
if (payloadElementTag == null) {
throw new IllegalStateException("TLV does not contain payload element tag");
}
TLVElement reqIdTag = payloadElementTag.getFirstChildElement(REQ_ID_TAG);
if (reqIdTag == null) {
throw new IllegalStateException("Payload element tag does not contain request ID tag");
}
return reqIdTag.getDecodedLong();
}
long getCorrelationId() {
return correlationId;
}
TLVElement getRequest() {
return request;
}
TLVElement getResponse() {
return response;
}
void responseReceived(TLVElement response) {
this.response = response;
availableResponse.offer(response);
ActiveTransactionsHolder.remove(this);
}
TLVElement waitResponse(long timeoutMs) throws InterruptedException {
return availableResponse.poll(timeoutMs, TimeUnit.MILLISECONDS);
}
WriteFuture send(IoSession session) {
return session.write(this);
}
@Override
public String toString() {
return "KSITCPTransaction [correlationId=" + correlationId + ", request=" + request + ", response=" + response + "]";
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy