aboutsummaryrefslogtreecommitdiff
path: root/app/src/main/java
diff options
context:
space:
mode:
Diffstat (limited to 'app/src/main/java')
-rw-r--r--app/src/main/java/org/pacien/tincapp/commands/Executor.kt17
-rw-r--r--app/src/main/java/org/pacien/tincapp/commands/Tincd.kt3
-rw-r--r--app/src/main/java/org/pacien/tincapp/service/TincVpnService.kt17
3 files changed, 25 insertions, 12 deletions
diff --git a/app/src/main/java/org/pacien/tincapp/commands/Executor.kt b/app/src/main/java/org/pacien/tincapp/commands/Executor.kt
index eace2e7..a3b5cea 100644
--- a/app/src/main/java/org/pacien/tincapp/commands/Executor.kt
+++ b/app/src/main/java/org/pacien/tincapp/commands/Executor.kt
@@ -13,6 +13,8 @@ import java.io.InputStreamReader
13 */ 13 */
14internal object Executor { 14internal object Executor {
15 15
16 private const val FAILED = -1
17
16 class CommandExecutionException(msg: String) : Exception(msg) 18 class CommandExecutionException(msg: String) : Exception(msg)
17 19
18 init { 20 init {
@@ -20,14 +22,23 @@ internal object Executor {
20 } 22 }
21 23
22 /** 24 /**
23 * @return -1 on error, forked child PID otherwise 25 * @return FAILED (-1) on error, forked child PID otherwise
24 */ 26 */
25 private external fun forkExec(argcv: Array<String>): Int 27 private external fun forkExec(argcv: Array<String>): Int
26 28
29 /**
30 * @return FAILED (-1) on error, 0 on no-op, the supplied PID otherwise
31 */
32 private external fun wait(pid: Int): Int
33
27 private fun read(stream: InputStream) = BufferedReader(InputStreamReader(stream)).readLines() 34 private fun read(stream: InputStream) = BufferedReader(InputStreamReader(stream)).readLines()
28 35
29 fun forkExec(cmd: Command) { 36 fun forkExec(cmd: Command): CompletableFuture<Void> {
30 if (forkExec(cmd.asArray()) == -1) throw CommandExecutionException("Could not fork child process.") 37 val pid = forkExec(cmd.asArray())
38 return when (pid) {
39 FAILED -> CompletableFuture.failedFuture(CommandExecutionException("Could not fork child process."))
40 else -> CompletableFuture.runAsync { wait(pid) }
41 }
31 } 42 }
32 43
33 fun call(cmd: Command): CompletableFuture<List<String>> { 44 fun call(cmd: Command): CompletableFuture<List<String>> {
diff --git a/app/src/main/java/org/pacien/tincapp/commands/Tincd.kt b/app/src/main/java/org/pacien/tincapp/commands/Tincd.kt
index d9c665d..44fcef5 100644
--- a/app/src/main/java/org/pacien/tincapp/commands/Tincd.kt
+++ b/app/src/main/java/org/pacien/tincapp/commands/Tincd.kt
@@ -7,7 +7,7 @@ import org.pacien.tincapp.context.AppPaths
7 */ 7 */
8object Tincd { 8object Tincd {
9 9
10 fun start(netName: String, deviceFd: Int, ed25519PrivateKeyFd: Int? = null, rsaPrivateKeyFd: Int? = null) { 10 fun start(netName: String, deviceFd: Int, ed25519PrivateKeyFd: Int? = null, rsaPrivateKeyFd: Int? = null) =
11 Executor.forkExec(Command(AppPaths.tincd().absolutePath) 11 Executor.forkExec(Command(AppPaths.tincd().absolutePath)
12 .withOption("no-detach") 12 .withOption("no-detach")
13 .withOption("config", AppPaths.confDir(netName).absolutePath) 13 .withOption("config", AppPaths.confDir(netName).absolutePath)
@@ -17,6 +17,5 @@ object Tincd {
17 .withOption("option", "Device=" + deviceFd) 17 .withOption("option", "Device=" + deviceFd)
18 .apply { if (ed25519PrivateKeyFd != null) withOption("option", "Ed25519PrivateKeyFile=/proc/self/fd/$ed25519PrivateKeyFd") } 18 .apply { if (ed25519PrivateKeyFd != null) withOption("option", "Ed25519PrivateKeyFile=/proc/self/fd/$ed25519PrivateKeyFd") }
19 .apply { if (rsaPrivateKeyFd != null) withOption("option", "PrivateKeyFile=/proc/self/fd/$rsaPrivateKeyFd") }) 19 .apply { if (rsaPrivateKeyFd != null) withOption("option", "PrivateKeyFile=/proc/self/fd/$rsaPrivateKeyFd") })
20 }
21 20
22} 21}
diff --git a/app/src/main/java/org/pacien/tincapp/service/TincVpnService.kt b/app/src/main/java/org/pacien/tincapp/service/TincVpnService.kt
index 278d20a..ec0512a 100644
--- a/app/src/main/java/org/pacien/tincapp/service/TincVpnService.kt
+++ b/app/src/main/java/org/pacien/tincapp/service/TincVpnService.kt
@@ -6,6 +6,7 @@ import android.net.Uri
6import android.net.VpnService 6import android.net.VpnService
7import android.os.ParcelFileDescriptor 7import android.os.ParcelFileDescriptor
8import android.util.Log 8import android.util.Log
9import java8.util.concurrent.CompletableFuture
9import org.apache.commons.configuration2.ex.ConversionException 10import org.apache.commons.configuration2.ex.ConversionException
10import org.bouncycastle.openssl.PEMException 11import org.bouncycastle.openssl.PEMException
11import org.pacien.tincapp.BuildConfig 12import org.pacien.tincapp.BuildConfig
@@ -82,8 +83,8 @@ class TincVpnService : VpnService() {
82 return reportError(resources.getString(R.string.message_could_not_decrypt_private_keys_format, e.message)) 83 return reportError(resources.getString(R.string.message_could_not_decrypt_private_keys_format, e.message))
83 } 84 }
84 85
85 Tincd.start(netName, deviceFd!!.fd, privateKeys.first?.fd, privateKeys.second?.fd) 86 val daemon = Tincd.start(netName, deviceFd!!.fd, privateKeys.first?.fd, privateKeys.second?.fd)
86 setState(true, netName, interfaceCfg, deviceFd) 87 setState(netName, interfaceCfg, deviceFd, daemon)
87 Log.i(TAG, "tinc daemon started.") 88 Log.i(TAG, "tinc daemon started.")
88 } 89 }
89 90
@@ -111,16 +112,17 @@ class TincVpnService : VpnService() {
111 112
112 val TAG = this::class.java.canonicalName!! 113 val TAG = this::class.java.canonicalName!!
113 114
114 private var connected: Boolean = false
115 private var netName: String? = null 115 private var netName: String? = null
116 private var interfaceCfg: VpnInterfaceConfiguration? = null 116 private var interfaceCfg: VpnInterfaceConfiguration? = null
117 private var fd: ParcelFileDescriptor? = null 117 private var fd: ParcelFileDescriptor? = null
118 private var daemon: CompletableFuture<Void>? = null
118 119
119 private fun setState(connected: Boolean, netName: String?, interfaceCfg: VpnInterfaceConfiguration?, fd: ParcelFileDescriptor?) { 120 private fun setState(netName: String?, interfaceCfg: VpnInterfaceConfiguration?,
120 TincVpnService.connected = connected 121 fd: ParcelFileDescriptor?, daemon: CompletableFuture<Void>?) {
121 TincVpnService.netName = netName 122 TincVpnService.netName = netName
122 TincVpnService.interfaceCfg = interfaceCfg 123 TincVpnService.interfaceCfg = interfaceCfg
123 TincVpnService.fd = fd 124 TincVpnService.fd = fd
125 TincVpnService.daemon = daemon
124 } 126 }
125 127
126 fun startVpn(netName: String, passphrase: String? = null) { 128 fun startVpn(netName: String, passphrase: String? = null) {
@@ -132,18 +134,19 @@ class TincVpnService : VpnService() {
132 try { 134 try {
133 Log.i(TAG, "Stopping any running tinc daemon.") 135 Log.i(TAG, "Stopping any running tinc daemon.")
134 if (netName != null) Tinc.stop(netName!!) 136 if (netName != null) Tinc.stop(netName!!)
137 daemon?.get()
135 fd?.close() 138 fd?.close()
136 Log.i(TAG, "All tinc daemons stopped.") 139 Log.i(TAG, "All tinc daemons stopped.")
137 } catch (e: IOException) { 140 } catch (e: IOException) {
138 Log.wtf(TAG, e) 141 Log.wtf(TAG, e)
139 } finally { 142 } finally {
140 setState(false, null, null, null) 143 setState(null, null, null, null)
141 } 144 }
142 } 145 }
143 146
144 fun getCurrentNetName() = netName 147 fun getCurrentNetName() = netName
145 fun getCurrentInterfaceCfg() = interfaceCfg 148 fun getCurrentInterfaceCfg() = interfaceCfg
146 fun isConnected() = connected 149 fun isConnected() = !(daemon?.isDone ?: true)
147 150
148 } 151 }
149 152