![JAR search and dependency download from the Maven repository](/logo.png)
com.r3.conclave.host.internal.NativeHostEnclaveInterface.kt Maven / Gradle / Ivy
The newest version!
package com.r3.conclave.host.internal
import com.r3.conclave.common.internal.*
import com.r3.conclave.utilities.internal.getAllBytes
import java.nio.ByteBuffer
import kotlin.collections.ArrayDeque
typealias StackFrame = CallInterfaceStackFrame
/**
* This class is the implementation of the [HostEnclaveInterface] for native enclaves.
* It has three jobs:
* - Serve as the endpoint for calls to make to the enclave, see [com.r3.conclave.common.internal.CallInterface]
* - Route calls from the enclave to the appropriate host side call handler, see [com.r3.conclave.common.internal.CallInterface]
* - Handle the low-level details of the messaging protocol (ECalls and OCalls).
*/
class NativeHostEnclaveInterface(private val enclaveId: Long) : CallInterface() {
/**
* Each thread has a lazily created stack which contains a frame for the currently active enclave call.
* When a message arrives from the enclave, this stack is used to associate the return value with the corresponding call.
*/
private val threadLocalStacks = ThreadLocal.withInitial { ArrayDeque() }
private val stack get() = threadLocalStacks.get()
private fun checkEnclaveID(id: Long) = check(id == this.enclaveId) { "Enclave ID mismatch" }
private fun checkCallType(type: EnclaveCallType) = check(type == stack.last().callType) { "Call type mismatch" }
/**
* Internal method for initiating an enclave call with specific arguments.
* This should not be called directly, but instead by implementations in [HostEnclaveInterface].
*/
override fun executeOutgoingCall(callType: EnclaveCallType, parameterBuffer: ByteBuffer): ByteBuffer? {
val stackFrame = StackFrame(callType, null, null)
stack.addLast(stackFrame)
NativeApi.sendECall(
enclaveId, callType.toByte(), CallInterfaceMessageType.CALL.toByte(), parameterBuffer.getAllBytes(avoidCopying = true))
/** If the stack frame is not the one we pushed earlier, something funky has happened! */
check(stackFrame === stack.removeLast()) {
"Wrong stack frame popped during enclave call, something isn't right!"
}
if (stack.isEmpty()) {
threadLocalStacks.remove()
}
stackFrame.exceptionBuffer?.let {
throw ThrowableSerialisation.deserialise(it)
}
return stackFrame.returnBuffer
}
/**
* Handler low level messages arriving from the enclave.
*/
fun handleOCall(enclaveId: Long, callTypeID: Byte, ocallType: CallInterfaceMessageType, data: ByteBuffer) {
checkEnclaveID(enclaveId)
when (ocallType) {
CallInterfaceMessageType.CALL -> handleCallOCall(HostCallType.fromByte(callTypeID), data)
CallInterfaceMessageType.RETURN -> handleReturnOCall(EnclaveCallType.fromByte(callTypeID), data)
CallInterfaceMessageType.EXCEPTION -> handleExceptionOCall(EnclaveCallType.fromByte(callTypeID), data)
}
}
/**
* Handle call initiations from the enclave.
* This method propagates the call to the appropriate host side call handler. If a return value is produced or an
* exception occurs, a reply message is sent back to the enclave.
*/
private fun handleCallOCall(callType: HostCallType, parameterBuffer: ByteBuffer) {
try {
val returnBuffer = handleIncomingCall(callType, parameterBuffer)
/**
* If there was a non-null return value, send it back to the enclave.
* If no value is received by the enclave, then [com.r3.conclave.enclave.internal.NativeEnclaveHostInterface.executeOutgoingCall]
* will return null to the caller on the enclave side.
*/
if (returnBuffer != null) {
NativeApi.sendECall(enclaveId, callType.toByte(), CallInterfaceMessageType.RETURN.toByte(), returnBuffer.getAllBytes(avoidCopying = true))
}
} catch (throwable: Throwable) {
val serializedException = ThrowableSerialisation.serialise(throwable)
NativeApi.sendECall(enclaveId, callType.toByte(), CallInterfaceMessageType.EXCEPTION.toByte(), serializedException)
}
}
/**
* Handle return messages originating from the enclave.
*/
private fun handleReturnOCall(callType: EnclaveCallType, returnBuffer: ByteBuffer) {
checkCallType(callType)
stack.last().returnBuffer = ByteBuffer.wrap(returnBuffer.getAllBytes())
}
/**
* Handle exception messages originating from the enclave.
*/
private fun handleExceptionOCall(callType: EnclaveCallType, exceptionBuffer: ByteBuffer) {
checkCallType(callType)
stack.last().exceptionBuffer = ByteBuffer.wrap(exceptionBuffer.getAllBytes())
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy