All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.r3.conclave.host.internal.EnclaveHostService.kt Maven / Gradle / Ivy

The newest version!
package com.r3.conclave.host.internal

import com.r3.conclave.host.AttestationParameters
import com.r3.conclave.host.EnclaveHost
import com.r3.conclave.host.MailCommand.PostMail
import com.r3.conclave.host.MailCommand.StoreSealedState
import com.r3.conclave.host.kds.KDSConfiguration
import java.nio.file.Path
import java.util.*

/**
 * Abstract class which provides the framework for a host to behave in the manner expected from `EnclaveClient` and
 * `EnclaveTransport`.
 *
 * We may decide that this is always how a host should behave in which this class should be moved to the public API or
 * embedded into [EnclaveHost].
 */
// TODO Mail command transactionality
abstract class EnclaveHostService : AutoCloseable {
    // This thread local holds the first synchronous mail response the enclave makes to the request mail sent to
    // "deliverMail". A synchronous response is one the enclave creates back to the sender. The sender is defined by
    // the routing hint (from the PoV of the host) and so the mail commands callback will look to see if any post mail
    // command is for the same routing hint that was used in "deliverMail". Only the first response can be sent back.
    // If the enclave created multiple mail for the same routing hint then the subsequent ones are available as
    // "asychronous" responses.
    private val synchronousResponse = ThreadLocal()
    // An asychronous response is primarily one where the enclave produces a mail for a client who is not the sender of
    // the inbound mail. These mail are retrieved by the client by polling for them.
    private val asynchronousResponses = HashMap>()

    abstract val enclaveHost: EnclaveHost

    fun start(
        attestationParameters: AttestationParameters?,
        sealedState: ByteArray?,
        enclaveFileSystemFile: Path?,
        kdsConfiguration: KDSConfiguration?
    ) {
        enclaveHost.start(attestationParameters, sealedState, enclaveFileSystemFile, kdsConfiguration) { commands ->
            for (command in commands) {
                when (command) {
                    is PostMail -> processPostMail(command.routingHint, command.encryptedBytes)
                    is StoreSealedState -> storeSealedState(command.sealedState)
                }
            }
        }
    }

    abstract fun storeSealedState(sealedState: ByteArray)

    fun deliverMail(
        encryptedMail: ByteArray,
        routingHint: String,
        callback: ((ByteArray) -> ByteArray?)? = null
    ): ByteArray? {
        // Set the current routing hint so that the mail commands callback can know which of the post mail commands
        // is a sychronous response.
        synchronousResponse.set(routingHint)
        try {
            if (callback != null) {
                enclaveHost.deliverMail(encryptedMail, routingHint, callback)
            } else {
                enclaveHost.deliverMail(encryptedMail, routingHint)
            }
            // If the enclave produced a sychronous response then return it, otherwise return null.
            return synchronousResponse.get() as? ByteArray
        } finally {
            synchronousResponse.remove()
        }
    }

    fun pollMail(routingHint: String): ByteArray? {
        synchronized(asynchronousResponses) {
            val queue = asynchronousResponses[routingHint] ?: return null
            val mail = queue.poll()
            if (queue.isEmpty()) {
                // If there are no more mail for the given routing hint then remove the empty mapping.
                asynchronousResponses.remove(routingHint)
            }
            return mail
        }
    }

    private fun processPostMail(routingHint: String?, encryptedMail: ByteArray) {
        checkNotNull(routingHint) { "Null routing hint not supported by this host." }
        if (synchronousResponse.get() == routingHint) {
            synchronousResponse.set(encryptedMail)
        } else {
            synchronized(asynchronousResponses) {
                val queue = asynchronousResponses.computeIfAbsent(routingHint) { LinkedList() }
                queue += encryptedMail
            }
        }
    }

    override fun close() {
        enclaveHost.close()
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy