Vsock stuff for phoenixd
This commit is contained in:
parent
26bfc7d3f9
commit
a15db45e13
@ -16,6 +16,8 @@ plugins {
|
|||||||
kotlin("multiplatform") version Versions.kotlin
|
kotlin("multiplatform") version Versions.kotlin
|
||||||
kotlin("plugin.serialization") version Versions.kotlin
|
kotlin("plugin.serialization") version Versions.kotlin
|
||||||
id("app.cash.sqldelight") version Versions.sqlDelight
|
id("app.cash.sqldelight") version Versions.sqlDelight
|
||||||
|
`java-library`
|
||||||
|
id("org.bytedeco.gradle-javacpp-platform").version("1.5.10")
|
||||||
application
|
application
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -30,6 +32,7 @@ allprojects {
|
|||||||
maven("https://oss.sonatype.org/content/repositories/snapshots")
|
maven("https://oss.sonatype.org/content/repositories/snapshots")
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
google()
|
google()
|
||||||
|
maven("https://jitpack.io")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -108,10 +111,28 @@ kotlin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
sourceSets {
|
sourceSets {
|
||||||
|
val jvmMain by getting {
|
||||||
|
// Include the native source directory if needed
|
||||||
|
resources.srcDirs("src/commonMain/kotlin/fr/acinq/lightning/vsock/native")
|
||||||
|
}
|
||||||
commonMain {
|
commonMain {
|
||||||
kotlin.srcDir(buildVersionsTask.map { it.destinationDir })
|
kotlin.srcDir(buildVersionsTask.map { it.destinationDir })
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation("fr.acinq.lightning:lightning-kmp:${Versions.lightningKmp}")
|
implementation("com.github.raymond98.lightning-kmp:lightning-kmp:v1.6.2-FEECREDIT-8")
|
||||||
|
//implementation("com.github.raymond98.vsockj:vsockj-native:1.0.3")
|
||||||
|
//implementation("com.github.raymond98.vsockj:vsockj-core:1.0.3")
|
||||||
|
|
||||||
|
implementation("org.bytedeco:javacpp:1.5.10")
|
||||||
|
implementation(kotlin("stdlib-jdk8"))
|
||||||
|
implementation("org.bytedeco:javacv-platform:1.5.10")
|
||||||
|
implementation("org.bytedeco:javacpp-presets:1.5.10")
|
||||||
|
|
||||||
|
api("fr.acinq.bitcoin:bitcoin-kmp:${Versions.bitcoinKmpVersion}")
|
||||||
|
api("co.touchlab:kermit:${Versions.kermitLoggerVersion}")
|
||||||
|
api("org.jetbrains.kotlinx:kotlinx-datetime:${Versions.datetimeVersion}")
|
||||||
|
api(ktor("network"))
|
||||||
|
api(ktor("network-tls"))
|
||||||
|
|
||||||
// ktor serialization
|
// ktor serialization
|
||||||
implementation(ktor("serialization-kotlinx-json"))
|
implementation(ktor("serialization-kotlinx-json"))
|
||||||
// ktor server
|
// ktor server
|
||||||
@ -135,6 +156,7 @@ kotlin {
|
|||||||
jvmMain {
|
jvmMain {
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation("app.cash.sqldelight:sqlite-driver:${Versions.sqlDelight}")
|
implementation("app.cash.sqldelight:sqlite-driver:${Versions.sqlDelight}")
|
||||||
|
implementation("fr.acinq.secp256k1:secp256k1-kmp-jni-jvm:${Versions.secpJniJvmVersion}")
|
||||||
implementation(ktor("client-okhttp"))
|
implementation(ktor("client-okhttp"))
|
||||||
implementation("ch.qos.logback:logback-classic:1.2.3")
|
implementation("ch.qos.logback:logback-classic:1.2.3")
|
||||||
}
|
}
|
||||||
@ -198,6 +220,9 @@ kotlin {
|
|||||||
|
|
||||||
application {
|
application {
|
||||||
mainClass = "fr.acinq.lightning.bin.MainKt"
|
mainClass = "fr.acinq.lightning.bin.MainKt"
|
||||||
|
|
||||||
|
// Set java.library.path to include the directory where the shared library is generated
|
||||||
|
applicationDefaultJvmArgs = listOf("-Djava.library.path=${project.buildDir}/libs")
|
||||||
}
|
}
|
||||||
|
|
||||||
val cliScripts by tasks.register("cliScripts", CreateStartScripts::class) {
|
val cliScripts by tasks.register("cliScripts", CreateStartScripts::class) {
|
||||||
@ -211,6 +236,33 @@ tasks.startScripts {
|
|||||||
dependsOn(cliScripts)
|
dependsOn(cliScripts)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val compileNative by tasks.register<Exec>("compileNative") {
|
||||||
|
group = "build"
|
||||||
|
description = "Compile the native C++ code into a shared library"
|
||||||
|
|
||||||
|
val outputDir = file("${project.buildDir}/libs")
|
||||||
|
val nativeSourceDir = file("src/commonMain/kotlin/fr/acinq/lightning/vsock/native")
|
||||||
|
|
||||||
|
// Locate the JNI headers - adjust these paths based on your actual JDK location
|
||||||
|
val jdkHome = System.getenv("JAVA_HOME") ?: "/usr/lib/jvm/default-java"
|
||||||
|
val jniIncludeDir = file("$jdkHome/include")
|
||||||
|
val jniPlatformIncludeDir = file("$jniIncludeDir/linux") // or "win32" for Windows, "darwin" for macOS
|
||||||
|
|
||||||
|
inputs.dir(nativeSourceDir)
|
||||||
|
outputs.dir(outputDir)
|
||||||
|
|
||||||
|
commandLine("g++", "-I$jniIncludeDir", "-I$jniPlatformIncludeDir", "-shared", "-o", outputDir.resolve("libjniVSockImpl.so"), nativeSourceDir.resolve("VSockImpl.cpp"), "-fPIC")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure the native library is compiled before creating the distribution
|
||||||
|
tasks.withType<Tar> {
|
||||||
|
dependsOn(compileNative)
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.withType<Zip> {
|
||||||
|
dependsOn(compileNative)
|
||||||
|
}
|
||||||
|
|
||||||
distributions {
|
distributions {
|
||||||
main {
|
main {
|
||||||
distributionBaseName = "phoenix"
|
distributionBaseName = "phoenix"
|
||||||
@ -221,6 +273,7 @@ distributions {
|
|||||||
// forward std input when app is run via gradle (otherwise keyboard input will return EOF)
|
// forward std input when app is run via gradle (otherwise keyboard input will return EOF)
|
||||||
tasks.withType<JavaExec> {
|
tasks.withType<JavaExec> {
|
||||||
standardInput = System.`in`
|
standardInput = System.`in`
|
||||||
|
dependsOn(compileNative) //This should not be the case for all platforms
|
||||||
}
|
}
|
||||||
|
|
||||||
sqldelight {
|
sqldelight {
|
||||||
|
@ -1,9 +1,16 @@
|
|||||||
object Versions {
|
object Versions {
|
||||||
val kotlin = "1.9.23"
|
val kotlin = "1.9.23"
|
||||||
val lightningKmp = "1.7.0-FEECREDIT-8"
|
val lightningKmp = "1.7.0-FEECREDIT-8"
|
||||||
|
val lightningKmpTag = "v1.6.2-FEECREDIT-8"
|
||||||
val sqlDelight = "2.0.1"
|
val sqlDelight = "2.0.1"
|
||||||
val okio = "3.8.0"
|
val okio = "3.8.0"
|
||||||
val clikt = "4.2.2"
|
val clikt = "4.2.2"
|
||||||
val ktor = "2.3.8"
|
val ktor = "2.3.8"
|
||||||
fun ktor(module: String) = "io.ktor:ktor-$module:$ktor"
|
fun ktor(module: String) = "io.ktor:ktor-$module:$ktor"
|
||||||
|
|
||||||
|
//For local tests
|
||||||
|
val bitcoinKmpVersion = "0.19.0"
|
||||||
|
val kermitLoggerVersion = "2.0.2"
|
||||||
|
val datetimeVersion = "0.6.0"
|
||||||
|
val secpJniJvmVersion = "0.15.0"
|
||||||
}
|
}
|
@ -337,7 +337,7 @@ class Api(private val nodeParams: NodeParams, private val peer: Peer, private va
|
|||||||
is Either.Left -> call.respondText(res.value.message.toString())
|
is Either.Left -> call.respondText(res.value.message.toString())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
post("/splicein") {//Manual splice-in
|
post("splicein") {//Manual splice-in
|
||||||
val formParameters = call.receiveParameters()
|
val formParameters = call.receiveParameters()
|
||||||
val amountSat = formParameters.getLong("amountSat").msat //the splice in command will send all the balance in wallet
|
val amountSat = formParameters.getLong("amountSat").msat //the splice in command will send all the balance in wallet
|
||||||
val feerate = FeeratePerKw(FeeratePerByte(formParameters.getLong("feerateSatByte").sat))
|
val feerate = FeeratePerKw(FeeratePerByte(formParameters.getLong("feerateSatByte").sat))
|
||||||
|
@ -11,6 +11,7 @@ import com.github.ajalt.clikt.output.MordantHelpFormatter
|
|||||||
import com.github.ajalt.clikt.parameters.groups.OptionGroup
|
import com.github.ajalt.clikt.parameters.groups.OptionGroup
|
||||||
import com.github.ajalt.clikt.parameters.groups.provideDelegate
|
import com.github.ajalt.clikt.parameters.groups.provideDelegate
|
||||||
import com.github.ajalt.clikt.parameters.options.*
|
import com.github.ajalt.clikt.parameters.options.*
|
||||||
|
import com.github.ajalt.clikt.parameters.types.boolean
|
||||||
import com.github.ajalt.clikt.parameters.types.choice
|
import com.github.ajalt.clikt.parameters.types.choice
|
||||||
import com.github.ajalt.clikt.parameters.types.int
|
import com.github.ajalt.clikt.parameters.types.int
|
||||||
import com.github.ajalt.clikt.parameters.types.restrictTo
|
import com.github.ajalt.clikt.parameters.types.restrictTo
|
||||||
@ -40,7 +41,6 @@ import fr.acinq.lightning.bin.logs.stringTimestamp
|
|||||||
import fr.acinq.lightning.blockchain.electrum.ElectrumClient
|
import fr.acinq.lightning.blockchain.electrum.ElectrumClient
|
||||||
import fr.acinq.lightning.blockchain.electrum.ElectrumWatcher
|
import fr.acinq.lightning.blockchain.electrum.ElectrumWatcher
|
||||||
import fr.acinq.lightning.blockchain.mempool.MempoolSpaceClient
|
import fr.acinq.lightning.blockchain.mempool.MempoolSpaceClient
|
||||||
import fr.acinq.lightning.blockchain.mempool.MempoolSpaceWatcher
|
|
||||||
import fr.acinq.lightning.crypto.LocalKeyManager
|
import fr.acinq.lightning.crypto.LocalKeyManager
|
||||||
import fr.acinq.lightning.db.ChannelsDb
|
import fr.acinq.lightning.db.ChannelsDb
|
||||||
import fr.acinq.lightning.db.Databases
|
import fr.acinq.lightning.db.Databases
|
||||||
@ -54,6 +54,7 @@ import fr.acinq.lightning.utils.ServerAddress
|
|||||||
import fr.acinq.lightning.utils.msat
|
import fr.acinq.lightning.utils.msat
|
||||||
import fr.acinq.lightning.utils.sat
|
import fr.acinq.lightning.utils.sat
|
||||||
import fr.acinq.lightning.utils.toByteVector
|
import fr.acinq.lightning.utils.toByteVector
|
||||||
|
import fr.acinq.lightning.vsock.VsockServer
|
||||||
import fr.acinq.phoenix.db.*
|
import fr.acinq.phoenix.db.*
|
||||||
import io.ktor.http.*
|
import io.ktor.http.*
|
||||||
import io.ktor.server.application.*
|
import io.ktor.server.application.*
|
||||||
@ -66,7 +67,7 @@ import okio.buffer
|
|||||||
import okio.use
|
import okio.use
|
||||||
import kotlin.system.exitProcess
|
import kotlin.system.exitProcess
|
||||||
import kotlin.time.Duration.Companion.milliseconds
|
import kotlin.time.Duration.Companion.milliseconds
|
||||||
import kotlin.time.Duration.Companion.minutes
|
//import kotlin.time.Duration.Companion.minutes
|
||||||
import kotlin.time.Duration.Companion.seconds
|
import kotlin.time.Duration.Companion.seconds
|
||||||
|
|
||||||
|
|
||||||
@ -100,9 +101,9 @@ class Phoenixd : CliktCommand() {
|
|||||||
else -> error("unsupported chain")
|
else -> error("unsupported chain")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private val mempoolPollingInterval by option("--mempool-space-polling-interval-minutes", help = "Polling interval for mempool.space API", hidden = true)
|
/*private val mempoolPollingInterval by option("--mempool-space-polling-interval-minutes", help = "Polling interval for mempool.space API", hidden = true)
|
||||||
.int().convert { it.minutes }
|
.int().convert { it.minutes }
|
||||||
.default(10.minutes)
|
.default(10.minutes)*/
|
||||||
private val httpBindIp by option("--http-bind-ip", help = "Bind ip for the http api").default("127.0.0.1")
|
private val httpBindIp by option("--http-bind-ip", help = "Bind ip for the http api").default("127.0.0.1")
|
||||||
private val httpBindPort by option("--http-bind-port", help = "Bind port for the http api").int().default(9740)
|
private val httpBindPort by option("--http-bind-port", help = "Bind port for the http api").int().default(9740)
|
||||||
private val httpPassword by option("--http-password", help = "Password for the http api")
|
private val httpPassword by option("--http-password", help = "Password for the http api")
|
||||||
@ -126,6 +127,14 @@ class Phoenixd : CliktCommand() {
|
|||||||
value
|
value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Electrum has a list of testnet and mainnet servers we can use to randomly find available ones https://github.com/spesmilo/electrum/blob/afa1a4d22a31d23d088c6670e1588eed32f7114d/lib/network.py#L57
|
||||||
|
private val electrumServerIp by option("--electrum-server-ip", help = "An IP for the Electrum server").default("testnet.qtornado.com")
|
||||||
|
private val electrumServerPort by option("--electrum-server-port", help = "Port for the electrum server").int().default(51002)
|
||||||
|
|
||||||
|
private val startVsock by option("--start-vsock-server", help = "Start the vsock server for API calls").boolean().default(true)
|
||||||
|
private val vsockCID by option("--vsock-server-cid", help = "CID for the Vsock server").int().default(4)
|
||||||
|
private val vsockPort by option("--vsock-server-port", help = "Port for the Vsock server").int().default(9001)
|
||||||
|
|
||||||
class LiquidityOptions : OptionGroup(name = "Liquidity Options") {
|
class LiquidityOptions : OptionGroup(name = "Liquidity Options") {
|
||||||
val autoLiquidity by option("--auto-liquidity", help = "Amount automatically requested when inbound liquidity is needed").choice(
|
val autoLiquidity by option("--auto-liquidity", help = "Amount automatically requested when inbound liquidity is needed").choice(
|
||||||
"off" to 0.sat,
|
"off" to 0.sat,
|
||||||
@ -133,7 +142,7 @@ class Phoenixd : CliktCommand() {
|
|||||||
"5m" to 5_000_000.sat,
|
"5m" to 5_000_000.sat,
|
||||||
"10m" to 10_000_000.sat,
|
"10m" to 10_000_000.sat,
|
||||||
).default(2_000_000.sat, "2m")
|
).default(2_000_000.sat, "2m")
|
||||||
val maxAbsoluteFee by option("--max-absolute-fee", hidden = true).deprecated("--max-absolute-fee is deprecated, use --max-mining-fee instead", error = true)
|
//val maxAbsoluteFee by option("--max-absolute-fee", hidden = true).deprecated("--max-absolute-fee is deprecated, use --max-mining-fee instead", error = true)
|
||||||
val maxMiningFee by option("--max-mining-fee", help = "Max mining fee for on-chain operations, in satoshis")
|
val maxMiningFee by option("--max-mining-fee", help = "Max mining fee for on-chain operations, in satoshis")
|
||||||
.int().convert { it.sat }
|
.int().convert { it.sat }
|
||||||
.restrictTo(5_000.sat..200_000.sat)
|
.restrictTo(5_000.sat..200_000.sat)
|
||||||
@ -276,7 +285,7 @@ class Phoenixd : CliktCommand() {
|
|||||||
//val watcher = MempoolSpaceWatcher(mempoolSpace, scope, loggerFactory, pollingInterval = mempoolPollingInterval)
|
//val watcher = MempoolSpaceWatcher(mempoolSpace, scope, loggerFactory, pollingInterval = mempoolPollingInterval)
|
||||||
|
|
||||||
val electrumClient = ElectrumClient(scope, nodeParams.loggerFactory)
|
val electrumClient = ElectrumClient(scope, nodeParams.loggerFactory)
|
||||||
val serverAddress = ServerAddress("electrum.acinq.co", 50002, TcpSocket.TLS.UNSAFE_CERTIFICATES)
|
val serverAddress = ServerAddress(electrumServerIp, electrumServerPort, TcpSocket.TLS.UNSAFE_CERTIFICATES)
|
||||||
val socketBuilder = TcpSocket.Builder()
|
val socketBuilder = TcpSocket.Builder()
|
||||||
|
|
||||||
runBlocking {
|
runBlocking {
|
||||||
@ -382,6 +391,12 @@ class Phoenixd : CliktCommand() {
|
|||||||
peer.setAutoLiquidityParams(liquidityOptions.autoLiquidity)
|
peer.setAutoLiquidityParams(liquidityOptions.autoLiquidity)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var vsockServer: VsockServer? = null
|
||||||
|
if(startVsock){
|
||||||
|
vsockServer = VsockServer(vsockCID, vsockPort, httpBindPort, httpBindIp, loggerFactory)
|
||||||
|
vsockServer.start()
|
||||||
|
}
|
||||||
|
|
||||||
val server = embeddedServer(CIO, port = httpBindPort, host = httpBindIp,
|
val server = embeddedServer(CIO, port = httpBindPort, host = httpBindIp,
|
||||||
configure = {
|
configure = {
|
||||||
reuseAddress = true
|
reuseAddress = true
|
||||||
@ -409,6 +424,7 @@ class Phoenixd : CliktCommand() {
|
|||||||
peerConnectionLoop.cancel()
|
peerConnectionLoop.cancel()
|
||||||
peer.disconnect()
|
peer.disconnect()
|
||||||
server.stop()
|
server.stop()
|
||||||
|
vsockServer?.stop()
|
||||||
exitProcess(0)
|
exitProcess(0)
|
||||||
}
|
}
|
||||||
server.environment.monitor.subscribe(ApplicationStopped) { consoleLog(brightYellow("http server stopped")) }
|
server.environment.monitor.subscribe(ApplicationStopped) { consoleLog(brightYellow("http server stopped")) }
|
||||||
|
@ -42,9 +42,9 @@ data class LSP(val walletParams: WalletParams, val swapInXpub: String) {
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
is Chain.Testnet -> LSP(
|
is Chain.Testnet -> LSP(
|
||||||
swapInXpub = "tpubDAmCFB21J9ExKBRPDcVxSvGs9jtcf8U1wWWbS1xTYmnUsuUHPCoFdCnEGxLE3THSWcQE48GHJnyz8XPbYUivBMbLSMBifFd3G9KmafkM9og",
|
swapInXpub = "tpubDCbLTyj9J59ygFSXyFxssuCFzLLD6ccfQmGdEmwb4miv33NAa7VyRdhDBJRUcsR987cMRm8ufCvdXBphT79QAYWczZJ8mqHeKtrXeE9PVD5",
|
||||||
walletParams = WalletParams(
|
walletParams = WalletParams(
|
||||||
trampolineNode = NodeUri(PublicKey.fromHex("03933884aaf1d6b108397e5efe5c86bcf2d8ca8d2f700eda99db9214fc2712b134"), "13.248.222.197", 9735),
|
trampolineNode = NodeUri(PublicKey.fromHex("02cb140e651b9bef52dfe8976ac08336414373d738d161fcf479f98a1ae4416c92"), "10.0.0.137", 9735),
|
||||||
trampolineFees,
|
trampolineFees,
|
||||||
invoiceDefaultRoutingFees,
|
invoiceDefaultRoutingFees,
|
||||||
swapInParams
|
swapInParams
|
||||||
|
@ -78,6 +78,13 @@ sealed class ApiType {
|
|||||||
val deeplyConfirmed: Long
|
val deeplyConfirmed: Long
|
||||||
) : ApiType()
|
) : ApiType()
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class VsockApiRequest(
|
||||||
|
val method: String,
|
||||||
|
val params: Map<String, String> = emptyMap(),
|
||||||
|
val httpPassword: String
|
||||||
|
) : ApiType()
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class FinalWalletInfo(@SerialName("path") val path: String, @SerialName("xpub") val xpub: String) : ApiType()
|
data class FinalWalletInfo(@SerialName("path") val path: String, @SerialName("xpub") val xpub: String) : ApiType()
|
||||||
|
|
||||||
|
72
src/commonMain/kotlin/fr/acinq/lightning/vsock/BaseVSock.kt
Normal file
72
src/commonMain/kotlin/fr/acinq/lightning/vsock/BaseVSock.kt
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
package fr.acinq.lightning.vsock
|
||||||
|
|
||||||
|
import fr.acinq.lightning.vsock.native.VSockImpl
|
||||||
|
import java.io.Closeable
|
||||||
|
import java.io.IOException
|
||||||
|
import java.net.SocketException
|
||||||
|
|
||||||
|
abstract class BaseVSock : Closeable {
|
||||||
|
protected val closeLock: Any = Any()
|
||||||
|
|
||||||
|
protected var isClosed: Boolean = false
|
||||||
|
protected var created: Boolean = false
|
||||||
|
protected var bound: Boolean = false
|
||||||
|
private var implementation: VSockImpl? = null
|
||||||
|
|
||||||
|
@Throws(SocketException::class)
|
||||||
|
private fun createImplementation() {
|
||||||
|
implementation = VSockImpl()
|
||||||
|
implementation!!.create()
|
||||||
|
created = true
|
||||||
|
}
|
||||||
|
|
||||||
|
@Throws(SocketException::class)
|
||||||
|
fun getImplementation(): VSockImpl? {
|
||||||
|
if (!created) createImplementation()
|
||||||
|
return implementation
|
||||||
|
}
|
||||||
|
|
||||||
|
@Throws(SocketException::class)
|
||||||
|
fun setImplementation(): VSockImpl {
|
||||||
|
if (implementation == null) {
|
||||||
|
implementation = VSockImpl()
|
||||||
|
}
|
||||||
|
return implementation!!
|
||||||
|
}
|
||||||
|
|
||||||
|
@get:Throws(IOException::class)
|
||||||
|
val localCid: Int
|
||||||
|
get() = getImplementation()!!.getLocalCid()
|
||||||
|
|
||||||
|
@JvmOverloads
|
||||||
|
@Throws(IOException::class)
|
||||||
|
fun bind(address: VSockAddress?, backlog: Int = DEFAULT_BACKLOG) {
|
||||||
|
var backlog = backlog
|
||||||
|
if (isClosed) {
|
||||||
|
throw SocketException("Socket closed")
|
||||||
|
}
|
||||||
|
if (bound) {
|
||||||
|
throw SocketException("Socket already bound")
|
||||||
|
}
|
||||||
|
if (backlog <= 0) {
|
||||||
|
backlog = DEFAULT_BACKLOG
|
||||||
|
}
|
||||||
|
getImplementation()!!.bind(address)
|
||||||
|
getImplementation()!!.listen(backlog)
|
||||||
|
bound = true
|
||||||
|
}
|
||||||
|
|
||||||
|
@Synchronized
|
||||||
|
@Throws(IOException::class)
|
||||||
|
override fun close() {
|
||||||
|
synchronized(closeLock) {
|
||||||
|
if (isClosed) return
|
||||||
|
if (created) getImplementation()!!.close()
|
||||||
|
isClosed = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val DEFAULT_BACKLOG = 42
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,17 @@
|
|||||||
|
package fr.acinq.lightning.vsock
|
||||||
|
|
||||||
|
import java.io.IOException
|
||||||
|
import java.net.SocketException
|
||||||
|
|
||||||
|
class ServerVSock : BaseVSock() {
|
||||||
|
@Throws(IOException::class)
|
||||||
|
fun accept(): VSock {
|
||||||
|
if (isClosed) throw SocketException("Socket closed")
|
||||||
|
if (!bound) throw SocketException("Socket not bound")
|
||||||
|
val socket = VSock()
|
||||||
|
socket.setImplementation()
|
||||||
|
socket.getImplementation()?.let { getImplementation()!!.accept(it) }
|
||||||
|
socket.postAccept()
|
||||||
|
return socket
|
||||||
|
}
|
||||||
|
}
|
71
src/commonMain/kotlin/fr/acinq/lightning/vsock/VSock.kt
Normal file
71
src/commonMain/kotlin/fr/acinq/lightning/vsock/VSock.kt
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
package fr.acinq.lightning.vsock
|
||||||
|
|
||||||
|
import java.io.Closeable
|
||||||
|
import java.io.IOException
|
||||||
|
import java.net.SocketException
|
||||||
|
|
||||||
|
class VSock : BaseVSock, Closeable {
|
||||||
|
private var connected = false
|
||||||
|
|
||||||
|
@get:Throws(IOException::class)
|
||||||
|
@get:Synchronized
|
||||||
|
var outputStream: VSockOutputStream? = null
|
||||||
|
get() {
|
||||||
|
if (isClosed) {
|
||||||
|
throw SocketException("VSock is closed")
|
||||||
|
}
|
||||||
|
if (field == null) {
|
||||||
|
field = getImplementation()?.let { VSockOutputStream(it) }
|
||||||
|
}
|
||||||
|
return field
|
||||||
|
}
|
||||||
|
private set
|
||||||
|
|
||||||
|
@get:Throws(IOException::class)
|
||||||
|
@get:Synchronized
|
||||||
|
var inputStream: VSockInputStream? = null
|
||||||
|
get() {
|
||||||
|
if (isClosed) {
|
||||||
|
throw SocketException("VSock is closed")
|
||||||
|
}
|
||||||
|
if (field == null) {
|
||||||
|
field = getImplementation()?.let { VSockInputStream(it) }
|
||||||
|
}
|
||||||
|
return field
|
||||||
|
}
|
||||||
|
private set
|
||||||
|
|
||||||
|
constructor()
|
||||||
|
|
||||||
|
constructor(address: VSockAddress?) {
|
||||||
|
try {
|
||||||
|
getImplementation()!!.connect(address)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
try {
|
||||||
|
close()
|
||||||
|
} catch (ce: Exception) {
|
||||||
|
e.addSuppressed(ce)
|
||||||
|
}
|
||||||
|
throw IllegalStateException(e.message, e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Throws(SocketException::class)
|
||||||
|
fun connect(address: VSockAddress?) {
|
||||||
|
if (isClosed) {
|
||||||
|
throw SocketException("Socket closed")
|
||||||
|
}
|
||||||
|
if (connected) {
|
||||||
|
throw SocketException("Socket already connected")
|
||||||
|
}
|
||||||
|
getImplementation()!!.connect(address)
|
||||||
|
connected = true
|
||||||
|
bound = true
|
||||||
|
}
|
||||||
|
|
||||||
|
fun postAccept() {
|
||||||
|
created = true
|
||||||
|
bound = true
|
||||||
|
connected = true
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,35 @@
|
|||||||
|
package fr.acinq.lightning.vsock
|
||||||
|
|
||||||
|
import java.net.SocketAddress
|
||||||
|
import java.util.Objects
|
||||||
|
|
||||||
|
class VSockAddress(val cid: Int, val port: Int) : SocketAddress() {
|
||||||
|
override fun equals(o: Any?): Boolean {
|
||||||
|
if (this === o) return true
|
||||||
|
if (o == null || javaClass != o.javaClass) return false
|
||||||
|
val that = o as VSockAddress
|
||||||
|
return cid == that.cid &&
|
||||||
|
port == that.port
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hashCode(): Int {
|
||||||
|
return Objects.hash(cid, port)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun toString(): String {
|
||||||
|
return "VSockAddress{" +
|
||||||
|
"cid=" + cid +
|
||||||
|
", port=" + port +
|
||||||
|
'}'
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val VMADDR_CID_ANY: Int = -1
|
||||||
|
const val VMADDR_CID_HYPERVISOR: Int = 0
|
||||||
|
const val VMADDR_CID_RESERVED: Int = 1
|
||||||
|
const val VMADDR_CID_HOST: Int = 2
|
||||||
|
const val VMADDR_CID_PARENT: Int = 3
|
||||||
|
|
||||||
|
const val VMADDR_PORT_ANY: Int = -1
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,30 @@
|
|||||||
|
package fr.acinq.lightning.vsock
|
||||||
|
|
||||||
|
import fr.acinq.lightning.vsock.native.VSockImpl
|
||||||
|
import java.io.IOException
|
||||||
|
import java.io.InputStream
|
||||||
|
|
||||||
|
class VSockInputStream(private val vSock: VSockImpl) : InputStream() {
|
||||||
|
private lateinit var temp: ByteArray
|
||||||
|
|
||||||
|
@Throws(IOException::class)
|
||||||
|
override fun read(b: ByteArray, off: Int, len: Int): Int {
|
||||||
|
return vSock.read(b, off, len)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Throws(IOException::class)
|
||||||
|
override fun read(): Int {
|
||||||
|
temp = ByteArray(1)
|
||||||
|
val n = read(temp, 0, 1)
|
||||||
|
if (n <= 0) {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
return temp[0].toInt()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Throws(IOException::class)
|
||||||
|
override fun close() {
|
||||||
|
vSock.close()
|
||||||
|
super.close()
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,26 @@
|
|||||||
|
package fr.acinq.lightning.vsock
|
||||||
|
|
||||||
|
import fr.acinq.lightning.vsock.native.VSockImpl
|
||||||
|
import java.io.IOException
|
||||||
|
import java.io.OutputStream
|
||||||
|
|
||||||
|
class VSockOutputStream internal constructor(private val vSock: VSockImpl) : OutputStream() {
|
||||||
|
private val temp = ByteArray(1)
|
||||||
|
|
||||||
|
@Throws(IOException::class)
|
||||||
|
override fun write(b: Int) {
|
||||||
|
temp[0] = b.toByte()
|
||||||
|
this.write(temp, 0, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Throws(IOException::class)
|
||||||
|
override fun write(b: ByteArray, off: Int, len: Int) {
|
||||||
|
vSock.write(b, off, len)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Throws(IOException::class)
|
||||||
|
override fun close() {
|
||||||
|
vSock.close()
|
||||||
|
super.close()
|
||||||
|
}
|
||||||
|
}
|
96
src/commonMain/kotlin/fr/acinq/lightning/vsock/VsockMain.kt
Normal file
96
src/commonMain/kotlin/fr/acinq/lightning/vsock/VsockMain.kt
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
package fr.acinq.lightning.vsock
|
||||||
|
|
||||||
|
import fr.acinq.lightning.bin.json.ApiType.*
|
||||||
|
import fr.acinq.lightning.logging.LoggerFactory
|
||||||
|
import fr.acinq.lightning.logging.debug
|
||||||
|
import fr.acinq.lightning.logging.error
|
||||||
|
import io.ktor.client.*
|
||||||
|
import io.ktor.client.request.*
|
||||||
|
import io.ktor.client.statement.*
|
||||||
|
import io.ktor.http.*
|
||||||
|
import kotlinx.coroutines.DelicateCoroutinesApi
|
||||||
|
import kotlinx.coroutines.GlobalScope
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.serialization.json.Json
|
||||||
|
import java.io.IOException
|
||||||
|
import java.nio.charset.StandardCharsets
|
||||||
|
import java.util.Base64
|
||||||
|
|
||||||
|
class VsockServer(private val CID: Int, private val port: Int, httpBindPort: Int, host: String, loggerFactory: LoggerFactory) {
|
||||||
|
private var server: ServerVSock? = null
|
||||||
|
private val logger = loggerFactory.newLogger(this::class)
|
||||||
|
private val client = HttpClient()
|
||||||
|
private val apiBaseUrl: String = "${host}:${httpBindPort}"
|
||||||
|
private val bufferSize: Int = 4096
|
||||||
|
|
||||||
|
@OptIn(DelicateCoroutinesApi::class)
|
||||||
|
fun start() {
|
||||||
|
server = ServerVSock()
|
||||||
|
try {
|
||||||
|
server?.bind(VSockAddress(CID, port)) //For any CID use VSockAddress.VMADDR_CID_ANY
|
||||||
|
logger.debug { "Vsock Bound on Cid: ${server?.localCid}" }
|
||||||
|
|
||||||
|
server?.accept()?.use { peerVSock ->
|
||||||
|
val buffer = ByteArray(bufferSize)
|
||||||
|
val bytesRead = peerVSock.inputStream?.read(buffer, 0, bufferSize)
|
||||||
|
if (bytesRead != null) {
|
||||||
|
if (bytesRead > 0) {
|
||||||
|
val receivedData = String(buffer, 0, bytesRead, StandardCharsets.UTF_8).trim()
|
||||||
|
logger.debug { "Received Data: $receivedData" }
|
||||||
|
|
||||||
|
// Parse the received data into a http request
|
||||||
|
val apiRequest = try {
|
||||||
|
Json.decodeFromString<VsockApiRequest>(receivedData)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
logger.error { "Failed to parse JSON: ${e.message}" }
|
||||||
|
peerVSock.outputStream?.write("Invalid JSON format".toByteArray(StandardCharsets.UTF_8))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle the API call
|
||||||
|
GlobalScope.launch {
|
||||||
|
val response = handleApiCall(apiRequest)
|
||||||
|
peerVSock.outputStream?.write(response.toByteArray(StandardCharsets.UTF_8))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (ex: IOException) {
|
||||||
|
logger.error { "Error starting Vsock: ${ex.message}" }
|
||||||
|
} finally {
|
||||||
|
stop()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun handleApiCall(request: VsockApiRequest): String {
|
||||||
|
return try {
|
||||||
|
val url = "$apiBaseUrl/${request.method}"
|
||||||
|
val response: HttpResponse = client.get(url) {
|
||||||
|
headers {
|
||||||
|
append(HttpHeaders.Authorization, "Basic ${Base64.getEncoder().encodeToString("user:${request.httpPassword}".toByteArray())}")
|
||||||
|
}
|
||||||
|
url {
|
||||||
|
parameters.appendAll(Parameters.build {
|
||||||
|
request.params.forEach { (key, value) ->
|
||||||
|
append(key, value)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (response.status == HttpStatusCode.OK) {
|
||||||
|
response.bodyAsText()
|
||||||
|
} else {
|
||||||
|
"API Error: ${response.status} - ${response.bodyAsText()}"
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
logger.error { "API call failed: ${e.message}" }
|
||||||
|
"API call failed: ${e.message}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun stop() {
|
||||||
|
logger.debug { "Stopping Vsock Server" }
|
||||||
|
server?.close()
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,195 @@
|
|||||||
|
#include <jni.h>
|
||||||
|
#include "VSockImpl.h" // Include the generated JNI header
|
||||||
|
#include <iostream>
|
||||||
|
#include <cstring>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <linux/vm_sockets.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#define JVM_IO_INTR (-2)
|
||||||
|
#define BUFFER_LEN 65536
|
||||||
|
#define min(a, b) ((a) < (b) ? (a) : (b))
|
||||||
|
|
||||||
|
// Make sure to wrap all your JNI functions with extern "C" to avoid name mangling
|
||||||
|
extern "C" {
|
||||||
|
|
||||||
|
// Native method implementations matching the JNI header
|
||||||
|
|
||||||
|
JNIEXPORT void JNICALL
|
||||||
|
Java_fr_acinq_lightning_vsock_native_VSockImpl_socketCreate(JNIEnv *env, jobject thisObj) {
|
||||||
|
int fd = socket(AF_VSOCK, SOCK_STREAM, 0);
|
||||||
|
// Optionally store the socket descriptor in the Java object's field
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT void JNICALL
|
||||||
|
Java_fr_acinq_lightning_vsock_native_VSockImpl_connect(JNIEnv *env, jobject thisObj, jobject addr) {
|
||||||
|
int fd = -1; // Assuming you have stored the fd somewhere accessible
|
||||||
|
if (fd == -1) {
|
||||||
|
env->ThrowNew(env->FindClass("java/net/SocketException"), "Socket is closed");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the cid and port from the VSockAddress object
|
||||||
|
jclass VSockAddressClass = env->GetObjectClass(addr);
|
||||||
|
jfieldID cidField = env->GetFieldID(VSockAddressClass, "cid", "I");
|
||||||
|
jfieldID portField = env->GetFieldID(VSockAddressClass, "port", "I");
|
||||||
|
|
||||||
|
struct sockaddr_vm sock_addr;
|
||||||
|
std::memset(&sock_addr, 0, sizeof(struct sockaddr_vm));
|
||||||
|
sock_addr.svm_family = AF_VSOCK;
|
||||||
|
sock_addr.svm_port = env->GetIntField(addr, portField);
|
||||||
|
sock_addr.svm_cid = env->GetIntField(addr, cidField);
|
||||||
|
int status = ::connect(fd, (struct sockaddr *)&sock_addr, sizeof(struct sockaddr_vm));
|
||||||
|
|
||||||
|
if (status != 0) {
|
||||||
|
env->ThrowNew(env->FindClass("java/net/ConnectException"),
|
||||||
|
("Connect failed with error no: " + std::to_string(errno)).c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT void JNICALL
|
||||||
|
Java_fr_acinq_lightning_vsock_native_VSockImpl_close(JNIEnv *env, jobject thisObj) {
|
||||||
|
int fd = -1; // Assuming you have stored the fd somewhere accessible
|
||||||
|
if (fd == -1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int status = ::close(fd);
|
||||||
|
fd = -1;
|
||||||
|
|
||||||
|
if (status != 0) {
|
||||||
|
env->ThrowNew(env->FindClass("java/net/SocketException"),
|
||||||
|
("Close failed with error no: " + std::to_string(errno)).c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT void JNICALL
|
||||||
|
Java_fr_acinq_lightning_vsock_native_VSockImpl_write(JNIEnv *env, jobject thisObj, jbyteArray b, jint offset, jint len) {
|
||||||
|
int fd = -1; // Assuming you have stored the fd somewhere accessible
|
||||||
|
if (fd == -1) {
|
||||||
|
env->ThrowNew(env->FindClass("java/net/SocketException"), "Socket is closed");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
char BUF[BUFFER_LEN];
|
||||||
|
while (len > 0) {
|
||||||
|
int chunkLen = min(BUFFER_LEN, len);
|
||||||
|
env->GetByteArrayRegion(b, offset, chunkLen, (jbyte *)BUF);
|
||||||
|
|
||||||
|
int n = (int)::send(fd, BUF, chunkLen, 0);
|
||||||
|
if (n <= 0) {
|
||||||
|
env->ThrowNew(env->FindClass("java/net/SocketException"), "Write failed");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
len -= chunkLen;
|
||||||
|
offset += chunkLen;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jint JNICALL
|
||||||
|
Java_fr_acinq_lightning_vsock_native_VSockImpl_read(JNIEnv *env, jobject thisObj, jbyteArray b, jint offset, jint len) {
|
||||||
|
int fd = -1; // Assuming you have stored the fd somewhere accessible
|
||||||
|
if (fd == -1) {
|
||||||
|
env->ThrowNew(env->FindClass("java/net/SocketException"), "Socket is closed");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *bufP = (char *)malloc((size_t)len);
|
||||||
|
int nread = (int)::recv(fd, bufP, len, 0);
|
||||||
|
|
||||||
|
if (nread < 0) {
|
||||||
|
env->ThrowNew(env->FindClass("java/net/SocketException"),
|
||||||
|
("Read failed with error no: " + std::to_string(errno)).c_str());
|
||||||
|
free(bufP);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
env->SetByteArrayRegion(b, offset, nread, (jbyte *)bufP);
|
||||||
|
free(bufP);
|
||||||
|
return nread;
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT void JNICALL
|
||||||
|
Java_fr_acinq_lightning_vsock_native_VSockImpl_bind(JNIEnv *env, jobject thisObj, jobject addr) {
|
||||||
|
int fd = -1; // Assuming you have stored the fd somewhere accessible
|
||||||
|
if (fd == -1) {
|
||||||
|
env->ThrowNew(env->FindClass("java/net/SocketException"), "Socket is closed");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the cid and port from the VSockAddress object
|
||||||
|
jclass VSockAddressClass = env->GetObjectClass(addr);
|
||||||
|
jfieldID cidField = env->GetFieldID(VSockAddressClass, "cid", "I");
|
||||||
|
jfieldID portField = env->GetFieldID(VSockAddressClass, "port", "I");
|
||||||
|
|
||||||
|
struct sockaddr_vm sock_addr;
|
||||||
|
std::memset(&sock_addr, 0, sizeof(struct sockaddr_vm));
|
||||||
|
sock_addr.svm_family = AF_VSOCK;
|
||||||
|
sock_addr.svm_port = env->GetIntField(addr, portField);
|
||||||
|
sock_addr.svm_cid = env->GetIntField(addr, cidField);
|
||||||
|
|
||||||
|
int status = ::bind(fd, (struct sockaddr *)&sock_addr, sizeof(struct sockaddr_vm));
|
||||||
|
|
||||||
|
if (status != 0) {
|
||||||
|
env->ThrowNew(env->FindClass("java/net/BindException"),
|
||||||
|
("Bind failed with error no: " + std::to_string(errno)).c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT void JNICALL
|
||||||
|
Java_fr_acinq_lightning_vsock_native_VSockImpl_listen(JNIEnv *env, jobject thisObj, jint backlog) {
|
||||||
|
int fd = -1; // Assuming you have stored the fd somewhere accessible
|
||||||
|
if (fd == -1) {
|
||||||
|
env->ThrowNew(env->FindClass("java/net/SocketException"), "Socket is closed");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int status = ::listen(fd, backlog);
|
||||||
|
|
||||||
|
if (status != 0) {
|
||||||
|
env->ThrowNew(env->FindClass("java/net/SocketException"),
|
||||||
|
("Listen failed with error no: " + std::to_string(errno)).c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT void JNICALL
|
||||||
|
Java_fr_acinq_lightning_vsock_native_VSockImpl_accept(JNIEnv *env, jobject thisObj, jobject connectionVSock) {
|
||||||
|
int fd = -1; // Assuming you have stored the fd somewhere accessible
|
||||||
|
if (fd == -1) {
|
||||||
|
env->ThrowNew(env->FindClass("java/net/SocketException"), "Socket is closed");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct sockaddr_vm peer_addr;
|
||||||
|
socklen_t peer_addr_size = sizeof(struct sockaddr_vm);
|
||||||
|
int peer_fd = ::accept(fd, (struct sockaddr *)&peer_addr, &peer_addr_size);
|
||||||
|
|
||||||
|
if (peer_fd == -1) {
|
||||||
|
env->ThrowNew(env->FindClass("java/net/SocketException"),
|
||||||
|
("Accept failed with error no: " + std::to_string(errno)).c_str());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the peer_fd in the Java connectionVSock object
|
||||||
|
jclass VSockImplClass = env->GetObjectClass(connectionVSock);
|
||||||
|
jfieldID fdField = env->GetFieldID(VSockImplClass, "fd", "I");
|
||||||
|
env->SetIntField(connectionVSock, fdField, peer_fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jint JNICALL
|
||||||
|
Java_fr_acinq_lightning_vsock_native_VSockImpl_getLocalCid(JNIEnv *env, jobject thisObj) {
|
||||||
|
int fd = -1; // Assuming you have stored the fd somewhere accessible
|
||||||
|
if (fd == -1) {
|
||||||
|
env->ThrowNew(env->FindClass("java/net/SocketException"), "Socket is closed");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int cid;
|
||||||
|
ioctl(fd, IOCTL_VM_SOCKETS_GET_LOCAL_CID, &cid);
|
||||||
|
return (jint)cid;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // extern "C"
|
@ -0,0 +1,86 @@
|
|||||||
|
/* DO NOT EDIT THIS FILE - it is machine generated */
|
||||||
|
#include <jni.h>
|
||||||
|
/* Header for class fr_acinq_lightning_vsock_native_VSockImpl */
|
||||||
|
|
||||||
|
#ifndef _Included_fr_acinq_lightning_vsock_native_VSockImpl
|
||||||
|
#define _Included_fr_acinq_lightning_vsock_native_VSockImpl
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Class: fr_acinq_lightning_vsock_native_VSockImpl
|
||||||
|
* Method: socketCreate
|
||||||
|
* Signature: ()V
|
||||||
|
*/
|
||||||
|
JNIEXPORT void JNICALL Java_fr_acinq_lightning_vsock_native_VSockImpl_socketCreate
|
||||||
|
(JNIEnv *, jobject);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Class: fr_acinq_lightning_vsock_native_VSockImpl
|
||||||
|
* Method: connect
|
||||||
|
* Signature: (Lfr/acinq/lightning/vsock/VSockAddress;)V
|
||||||
|
*/
|
||||||
|
JNIEXPORT void JNICALL Java_fr_acinq_lightning_vsock_native_VSockImpl_connect
|
||||||
|
(JNIEnv *, jobject, jobject);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Class: fr_acinq_lightning_vsock_native_VSockImpl
|
||||||
|
* Method: close
|
||||||
|
* Signature: ()V
|
||||||
|
*/
|
||||||
|
JNIEXPORT void JNICALL Java_fr_acinq_lightning_vsock_native_VSockImpl_close
|
||||||
|
(JNIEnv *, jobject);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Class: fr_acinq_lightning_vsock_native_VSockImpl
|
||||||
|
* Method: write
|
||||||
|
* Signature: ([BII)V
|
||||||
|
*/
|
||||||
|
JNIEXPORT void JNICALL Java_fr_acinq_lightning_vsock_native_VSockImpl_write
|
||||||
|
(JNIEnv *, jobject, jbyteArray, jint, jint);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Class: fr_acinq_lightning_vsock_native_VSockImpl
|
||||||
|
* Method: read
|
||||||
|
* Signature: ([BII)I
|
||||||
|
*/
|
||||||
|
JNIEXPORT jint JNICALL Java_fr_acinq_lightning_vsock_native_VSockImpl_read
|
||||||
|
(JNIEnv *, jobject, jbyteArray, jint, jint);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Class: fr_acinq_lightning_vsock_native_VSockImpl
|
||||||
|
* Method: bind
|
||||||
|
* Signature: (Lfr/acinq/lightning/vsock/VSockAddress;)V
|
||||||
|
*/
|
||||||
|
JNIEXPORT void JNICALL Java_fr_acinq_lightning_vsock_native_VSockImpl_bind
|
||||||
|
(JNIEnv *, jobject, jobject);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Class: fr_acinq_lightning_vsock_native_VSockImpl
|
||||||
|
* Method: listen
|
||||||
|
* Signature: (I)V
|
||||||
|
*/
|
||||||
|
JNIEXPORT void JNICALL Java_fr_acinq_lightning_vsock_native_VSockImpl_listen
|
||||||
|
(JNIEnv *, jobject, jint);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Class: fr_acinq_lightning_vsock_native_VSockImpl
|
||||||
|
* Method: accept
|
||||||
|
* Signature: (Lfr/acinq/lightning/vsock/native/VSockImpl;)V
|
||||||
|
*/
|
||||||
|
JNIEXPORT void JNICALL Java_fr_acinq_lightning_vsock_native_VSockImpl_accept
|
||||||
|
(JNIEnv *, jobject, jobject);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Class: fr_acinq_lightning_vsock_native_VSockImpl
|
||||||
|
* Method: getLocalCid
|
||||||
|
* Signature: ()I
|
||||||
|
*/
|
||||||
|
JNIEXPORT jint JNICALL Java_fr_acinq_lightning_vsock_native_VSockImpl_getLocalCid
|
||||||
|
(JNIEnv *, jobject);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
@ -0,0 +1,59 @@
|
|||||||
|
package fr.acinq.lightning.vsock.native
|
||||||
|
|
||||||
|
import fr.acinq.lightning.vsock.VSockAddress
|
||||||
|
import org.bytedeco.javacpp.Loader
|
||||||
|
import org.bytedeco.javacpp.Pointer
|
||||||
|
import org.bytedeco.javacpp.annotation.Namespace
|
||||||
|
import org.bytedeco.javacpp.annotation.Platform
|
||||||
|
import java.net.SocketException
|
||||||
|
|
||||||
|
|
||||||
|
@Platform(include = [
|
||||||
|
"<sys/socket.h>",
|
||||||
|
"<sys/ioctl.h>",
|
||||||
|
"<linux/vm_sockets.h>",
|
||||||
|
"<unistd.h>",
|
||||||
|
"<errno.h>"
|
||||||
|
])
|
||||||
|
@Namespace("vsock")
|
||||||
|
class VSockImpl() : Pointer() {
|
||||||
|
|
||||||
|
init {
|
||||||
|
Loader.load() //load the native library
|
||||||
|
}
|
||||||
|
|
||||||
|
var fd: Int = -1
|
||||||
|
|
||||||
|
@Throws(SocketException::class)
|
||||||
|
fun create() {
|
||||||
|
socketCreate()
|
||||||
|
}
|
||||||
|
|
||||||
|
private external fun allocate()
|
||||||
|
|
||||||
|
private external fun socketCreate()
|
||||||
|
|
||||||
|
@Throws(Exception::class)
|
||||||
|
external fun connect(address: VSockAddress?)
|
||||||
|
|
||||||
|
@Throws(Exception::class)
|
||||||
|
external override fun close()
|
||||||
|
|
||||||
|
@Throws(Exception::class)
|
||||||
|
external fun write(b: ByteArray, offset: Int, len: Int)
|
||||||
|
|
||||||
|
@Throws(Exception::class)
|
||||||
|
external fun read(b: ByteArray, offset: Int, len: Int): Int
|
||||||
|
|
||||||
|
@Throws(Exception::class)
|
||||||
|
external fun bind(addr: fr.acinq.lightning.vsock.VSockAddress?)
|
||||||
|
|
||||||
|
@Throws(Exception::class)
|
||||||
|
external fun listen(backlog: Int)
|
||||||
|
|
||||||
|
@Throws(Exception::class)
|
||||||
|
external fun accept(peerVSock: VSockImpl)
|
||||||
|
|
||||||
|
@Throws(Exception::class)
|
||||||
|
external fun getLocalCid(): Int
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user