shoes 0.3.1

A multi-protocol proxy server.
Documentation
package com.shoesproxy

/**
 * JNI bridge to the shoes native proxy library.
 *
 * Call [init] once before using any other method. The native library is
 * loaded automatically when this object is first accessed.
 *
 * Example — starting the VPN inside a [android.net.VpnService]:
 * ```kotlin
 * class MyVpnService : VpnService() {
 *
 *     private var shoesHandle: Long = -1
 *
 *     override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
 *         ShoesNative.init("info")
 *
 *         val tunFd = Builder()
 *             .addAddress("10.0.0.1", 24)
 *             .establish()!!
 *             .detachFd()
 *
 *         val config = """
 *             tun:
 *               device_fd: $tunFd
 *         """.trimIndent()
 *
 *         shoesHandle = ShoesNative.start(config) { fd -> protect(fd) }
 *         return START_STICKY
 *     }
 *
 *     override fun onDestroy() {
 *         ShoesNative.stop(shoesHandle)
 *         super.onDestroy()
 *     }
 * }
 * ```
 */
object ShoesNative {

    init {
        System.loadLibrary("shoes")
    }

    /**
     * Functional interface for protecting sockets from VPN routing.
     *
     * Implement this to delegate to [android.net.VpnService.protect], which
     * exempts the socket from being captured by the VPN tunnel — preventing
     * traffic loops.
     */
    fun interface SocketProtector {
        /**
         * Protect the given socket file descriptor.
         *
         * @param fd File descriptor of the socket to protect.
         * @return true if protection succeeded.
         */
        fun protect(fd: Int): Boolean
    }

    /**
     * Initialize the shoes library.
     *
     * Must be called once before [start]. Safe to call from any thread.
     * Repeated calls are no-ops.
     *
     * @param logLevel Desired verbosity: "error", "warn", "info", "debug", or "trace".
     * @return 0 on success, -1 on error.
     */
    external fun init(logLevel: String): Int

    /**
     * Get the shoes library version string (e.g. "0.2.8").
     */
    external fun getVersion(): String

    /**
     * Redirect log output to a file.
     *
     * Call after [init] to persist logs to disk.
     *
     * @param logPath Absolute path to the log file.
     * @return 0 on success, -1 on error.
     */
    external fun setLogFile(logPath: String): Int

    /**
     * Start the shoes VPN service.
     *
     * Spawns a background async runtime. The [configYaml] must include a
     * `tun` section with `device_fd` set to the TUN file descriptor obtained
     * from [android.net.VpnService.Builder.establish].
     *
     * @param configYaml YAML configuration string.
     * @param protectCallback Called by the engine to exempt outbound sockets
     *                        from VPN routing (pass `this::protect` from your VpnService).
     * @return A positive handle on success, -1 on error.
     */
    external fun start(configYaml: String, protectCallback: SocketProtector): Long

    /**
     * Stop the VPN service.
     *
     * Signals shutdown and blocks until the service has fully stopped.
     *
     * @param handle The handle returned by [start].
     */
    external fun stop(handle: Long)

    /**
     * Check whether the VPN service is currently running.
     *
     * @return true if the service is active.
     */
    external fun isRunning(): Boolean
}