summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorEmīls Piņķis <emils@mullvad.net>2018-08-29 17:08:03 +0100
committerEmīls Piņķis <emils@mullvad.net>2018-08-29 17:08:03 +0100
commitc0b41134ac1c7e9162c8f42121c3c809e421ce50 (patch)
tree9afb4b14db5feac02399467efb870a929166db90
parent559a81c6044d620159d8229295bee3b2e909eca4 (diff)
parentf47b02cfd9119392b6b39f8a0c9426d4b17575bd (diff)
downloadmullvadvpn-c0b41134ac1c7e9162c8f42121c3c809e421ce50.tar.xz
mullvadvpn-c0b41134ac1c7e9162c8f42121c3c809e421ce50.zip
Merge branch 'swap-ws-to-ipc'
-rw-r--r--CHANGELOG.md2
-rw-r--r--Cargo.lock353
-rw-r--r--README.md8
-rw-r--r--gui/packages/desktop/package.json4
-rw-r--r--gui/packages/desktop/src/common/types.js6
-rw-r--r--gui/packages/desktop/src/main/index.js40
-rw-r--r--gui/packages/desktop/src/main/rpc-address-file.js112
-rw-r--r--gui/packages/desktop/src/main/tempdir.js20
-rw-r--r--gui/packages/desktop/src/renderer/app.js41
-rw-r--r--gui/packages/desktop/src/renderer/lib/daemon-rpc.js13
-rw-r--r--gui/packages/desktop/src/renderer/lib/jsonrpc-client.js (renamed from gui/packages/desktop/src/renderer/lib/jsonrpc-transport.js)205
-rw-r--r--gui/packages/desktop/test/jsonrpc-transport.spec.js11
-rw-r--r--gui/yarn.lock19
-rw-r--r--mullvad-cli/Cargo.toml2
-rw-r--r--mullvad-cli/src/cmds/account.rs7
-rw-r--r--mullvad-cli/src/cmds/auto_connect.rs7
-rw-r--r--mullvad-cli/src/cmds/connect.rs4
-rw-r--r--mullvad-cli/src/cmds/disconnect.rs4
-rw-r--r--mullvad-cli/src/cmds/lan.rs8
-rw-r--r--mullvad-cli/src/cmds/relay.rs9
-rw-r--r--mullvad-cli/src/cmds/status.rs5
-rw-r--r--mullvad-cli/src/cmds/tunnel.rs9
-rw-r--r--mullvad-cli/src/cmds/version.rs6
-rw-r--r--mullvad-cli/src/main.rs9
-rw-r--r--mullvad-daemon/Cargo.toml8
-rw-r--r--mullvad-daemon/src/main.rs36
-rw-r--r--mullvad-daemon/src/management_interface.rs156
-rw-r--r--mullvad-daemon/src/rpc_address_file.rs88
-rw-r--r--mullvad-daemon/src/rpc_uniqueness_check.rs5
-rw-r--r--mullvad-ipc-client/Cargo.toml7
-rw-r--r--mullvad-ipc-client/src/lib.rs310
-rw-r--r--mullvad-paths/src/lib.rs2
-rw-r--r--mullvad-paths/src/rpc_address.rs26
-rw-r--r--mullvad-tests/Cargo.toml4
-rw-r--r--mullvad-tests/src/lib.rs90
-rw-r--r--mullvad-tests/tests/connection.rs112
-rw-r--r--mullvad-tests/tests/startup.rs55
-rw-r--r--talpid-core/Cargo.toml4
-rw-r--r--talpid-core/src/tunnel/openvpn.rs102
-rw-r--r--talpid-ipc/Cargo.toml15
-rw-r--r--talpid-ipc/src/client.rs585
-rw-r--r--talpid-ipc/src/lib.rs78
-rw-r--r--talpid-ipc/tests/ipc-client-server.rs54
-rw-r--r--talpid-openvpn-plugin/Cargo.toml5
-rw-r--r--talpid-openvpn-plugin/src/lib.rs55
-rw-r--r--talpid-openvpn-plugin/src/processing.rs71
46 files changed, 926 insertions, 1846 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 7808adbf2b..32332e8524 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -39,6 +39,8 @@ Line wrap the file at 100 chars. Th
having a create account form first.
- The CLI command to list relays is now shorter, `mullvad relay list` instead of
`mullvad relay list locations`.
+- Replace WebSockets with Unix domain sockets/Named pipes for IPC. The location
+ of the socket can be controlled with `MULLVAD_RPC_SOCKET_PATH`.
### Fixed
- Fix incorrect window position when using external display.
diff --git a/Cargo.lock b/Cargo.lock
index 78db2ce95c..5a1b732b08 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -440,6 +440,18 @@ dependencies = [
]
[[package]]
+name = "globset"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "aho-corasick 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "regex 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
name = "httparse"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -497,16 +509,6 @@ dependencies = [
]
[[package]]
-name = "idna"
-version = "0.1.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "matches 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
- "unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
- "unicode-normalization 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
name = "inotify"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -545,6 +547,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "jsonrpc-client-core"
version = "0.5.0"
+source = "git+https://github.com/mullvad/jsonrpc-client-rs#32c0d940f6e0ff0ee11690d746bfbfecd9345ed7"
+dependencies = [
+ "error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)",
+ "jsonrpc-core 8.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.71 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_json 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "jsonrpc-client-core"
+version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -569,9 +584,23 @@ dependencies = [
]
[[package]]
+name = "jsonrpc-client-ipc"
+version = "0.5.0"
+source = "git+https://github.com/mullvad/jsonrpc-client-rs#32c0d940f6e0ff0ee11690d746bfbfecd9345ed7"
+dependencies = [
+ "futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)",
+ "jsonrpc-client-core 0.5.0 (git+https://github.com/mullvad/jsonrpc-client-rs)",
+ "jsonrpc-server-utils 8.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "parity-tokio-ipc 0.1.5 (git+https://github.com/NikVolf/parity-tokio-ipc?rev=stable)",
+ "tokio 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-io 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
name = "jsonrpc-core"
version = "8.0.1"
-source = "git+https://github.com/paritytech/jsonrpc?tag=v8.0.1#01434b52bb7767c845c3cf43d545036e7680a263"
+source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -582,61 +611,73 @@ dependencies = [
[[package]]
name = "jsonrpc-core"
-version = "8.0.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
+version = "8.0.2"
+source = "git+https://github.com/paritytech/jsonrpc#98e892b07949b030461cd8781b2c7b635370327f"
dependencies = [
"futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)",
- "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.71 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.71 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
+name = "jsonrpc-ipc-server"
+version = "8.0.1"
+source = "git+https://github.com/paritytech/jsonrpc#98e892b07949b030461cd8781b2c7b635370327f"
+dependencies = [
+ "jsonrpc-core 8.0.2 (git+https://github.com/paritytech/jsonrpc)",
+ "jsonrpc-server-utils 8.0.1 (git+https://github.com/paritytech/jsonrpc)",
+ "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "parity-tokio-ipc 0.1.5 (git+https://github.com/nikvolf/parity-tokio-ipc?branch=stable)",
+ "parking_lot 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-service 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
name = "jsonrpc-macros"
-version = "8.0.0"
-source = "git+https://github.com/paritytech/jsonrpc?tag=v8.0.1#01434b52bb7767c845c3cf43d545036e7680a263"
+version = "8.0.1"
+source = "git+https://github.com/paritytech/jsonrpc#98e892b07949b030461cd8781b2c7b635370327f"
dependencies = [
- "jsonrpc-core 8.0.1 (git+https://github.com/paritytech/jsonrpc?tag=v8.0.1)",
- "jsonrpc-pubsub 8.0.0 (git+https://github.com/paritytech/jsonrpc?tag=v8.0.1)",
+ "jsonrpc-core 8.0.2 (git+https://github.com/paritytech/jsonrpc)",
+ "jsonrpc-pubsub 8.0.1 (git+https://github.com/paritytech/jsonrpc)",
"serde 1.0.71 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "jsonrpc-pubsub"
-version = "8.0.0"
-source = "git+https://github.com/paritytech/jsonrpc?tag=v8.0.1#01434b52bb7767c845c3cf43d545036e7680a263"
+version = "8.0.1"
+source = "git+https://github.com/paritytech/jsonrpc#98e892b07949b030461cd8781b2c7b635370327f"
dependencies = [
- "jsonrpc-core 8.0.1 (git+https://github.com/paritytech/jsonrpc?tag=v8.0.1)",
- "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
- "parking_lot 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
+ "jsonrpc-core 8.0.2 (git+https://github.com/paritytech/jsonrpc)",
+ "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "parking_lot 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "jsonrpc-server-utils"
version = "8.0.0"
-source = "git+https://github.com/paritytech/jsonrpc?tag=v8.0.1#01434b52bb7767c845c3cf43d545036e7680a263"
+source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bytes 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)",
"globset 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
- "jsonrpc-core 8.0.1 (git+https://github.com/paritytech/jsonrpc?tag=v8.0.1)",
+ "jsonrpc-core 8.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-io 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
-name = "jsonrpc-ws-server"
-version = "8.0.0"
-source = "git+https://github.com/paritytech/jsonrpc?tag=v8.0.1#01434b52bb7767c845c3cf43d545036e7680a263"
+name = "jsonrpc-server-utils"
+version = "8.0.1"
+source = "git+https://github.com/paritytech/jsonrpc#98e892b07949b030461cd8781b2c7b635370327f"
dependencies = [
- "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "jsonrpc-core 8.0.1 (git+https://github.com/paritytech/jsonrpc?tag=v8.0.1)",
- "jsonrpc-server-utils 8.0.0 (git+https://github.com/paritytech/jsonrpc?tag=v8.0.1)",
- "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
- "parking_lot 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
- "slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "ws 0.7.5 (git+https://github.com/tomusdrw/ws-rs)",
+ "bytes 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)",
+ "globset 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "jsonrpc-core 8.0.2 (git+https://github.com/paritytech/jsonrpc)",
+ "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-io 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -685,6 +726,15 @@ dependencies = [
]
[[package]]
+name = "lock_api"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
name = "log"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -709,11 +759,6 @@ dependencies = [
]
[[package]]
-name = "matches"
-version = "0.1.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
-[[package]]
name = "memchr"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -777,6 +822,27 @@ dependencies = [
]
[[package]]
+name = "mio-named-pipes"
+version = "0.1.6"
+source = "git+https://github.com/alexcrichton/mio-named-pipes#2072ae0de5b3632dbb065fcd9c8be6c6a2fc39ae"
+dependencies = [
+ "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "mio 0.6.15 (registry+https://github.com/rust-lang/crates.io-index)",
+ "miow 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "mio-uds"
+version = "0.6.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
+ "mio 0.6.15 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
name = "miow"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -799,6 +865,15 @@ dependencies = [
]
[[package]]
+name = "miow"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "socket2 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
name = "mnl"
version = "0.1.0"
source = "git+https://github.com/mullvad/mnl-rs#8ceadc9e4a43830cc78eb701453d44271b8628fe"
@@ -824,7 +899,9 @@ dependencies = [
"clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)",
"env_logger 0.5.12 (registry+https://github.com/rust-lang/crates.io-index)",
"error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)",
"mullvad-ipc-client 0.1.0",
+ "mullvad-paths 0.1.0",
"mullvad-types 0.1.0",
"serde 1.0.71 (registry+https://github.com/rust-lang/crates.io-index)",
"talpid-ipc 0.1.0",
@@ -842,10 +919,10 @@ dependencies = [
"error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
"fern 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
"futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)",
- "jsonrpc-core 8.0.1 (git+https://github.com/paritytech/jsonrpc?tag=v8.0.1)",
- "jsonrpc-macros 8.0.0 (git+https://github.com/paritytech/jsonrpc?tag=v8.0.1)",
- "jsonrpc-pubsub 8.0.0 (git+https://github.com/paritytech/jsonrpc?tag=v8.0.1)",
- "jsonrpc-ws-server 8.0.0 (git+https://github.com/paritytech/jsonrpc?tag=v8.0.1)",
+ "jsonrpc-core 8.0.2 (git+https://github.com/paritytech/jsonrpc)",
+ "jsonrpc-ipc-server 8.0.1 (git+https://github.com/paritytech/jsonrpc)",
+ "jsonrpc-macros 8.0.1 (git+https://github.com/paritytech/jsonrpc)",
+ "jsonrpc-pubsub 8.0.1 (git+https://github.com/paritytech/jsonrpc)",
"lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -875,11 +952,17 @@ name = "mullvad-ipc-client"
version = "0.1.0"
dependencies = [
"error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)",
+ "jsonrpc-client-core 0.5.0 (git+https://github.com/mullvad/jsonrpc-client-rs)",
+ "jsonrpc-client-ipc 0.5.0 (git+https://github.com/mullvad/jsonrpc-client-rs)",
+ "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
"mullvad-paths 0.1.0",
"mullvad-types 0.1.0",
"serde 1.0.71 (registry+https://github.com/rust-lang/crates.io-index)",
"talpid-ipc 0.1.0",
"talpid-types 0.1.0",
+ "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-timer 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -935,6 +1018,9 @@ name = "mullvad-tests"
version = "0.1.0"
dependencies = [
"duct 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)",
+ "jsonrpc-client-core 0.5.0 (git+https://github.com/mullvad/jsonrpc-client-rs)",
+ "jsonrpc-client-ipc 0.5.0 (git+https://github.com/mullvad/jsonrpc-client-rs)",
"libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
"mullvad-ipc-client 0.1.0",
"mullvad-paths 0.1.0",
@@ -943,6 +1029,7 @@ dependencies = [
"openvpn-plugin 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"talpid-ipc 0.1.0",
"tempfile 3.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -1112,11 +1199,47 @@ dependencies = [
]
[[package]]
+name = "parity-tokio-ipc"
+version = "0.1.5"
+source = "git+https://github.com/nikvolf/parity-tokio-ipc?branch=stable#b4a6cdf7d9b1e51c5d744d7f47d391a69a943232"
+dependencies = [
+ "bytes 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "mio-named-pipes 0.1.6 (git+https://github.com/alexcrichton/mio-named-pipes)",
+ "miow 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-io 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-named-pipes 0.1.0 (git+https://github.com/nikvolf/tokio-named-pipes?branch=stable)",
+ "tokio-uds 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "parity-tokio-ipc"
+version = "0.1.5"
+source = "git+https://github.com/NikVolf/parity-tokio-ipc?rev=stable#b4a6cdf7d9b1e51c5d744d7f47d391a69a943232"
+dependencies = [
+ "bytes 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "mio-named-pipes 0.1.6 (git+https://github.com/alexcrichton/mio-named-pipes)",
+ "miow 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-io 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-named-pipes 0.1.0 (git+https://github.com/nikvolf/tokio-named-pipes?branch=stable)",
+ "tokio-uds 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
name = "parking_lot"
-version = "0.4.8"
+version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "lock_api 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"parking_lot_core 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -1359,11 +1482,6 @@ dependencies = [
]
[[package]]
-name = "sha1"
-version = "0.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
-[[package]]
name = "shared_child"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1423,6 +1541,17 @@ dependencies = [
]
[[package]]
+name = "socket2"
+version = "0.3.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "cfg-if 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
+ "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
name = "stable_deref_trait"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1504,8 +1633,8 @@ dependencies = [
"failure 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)",
"ipnetwork 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "jsonrpc-core 8.0.1 (git+https://github.com/paritytech/jsonrpc?tag=v8.0.1)",
- "jsonrpc-macros 8.0.0 (git+https://github.com/paritytech/jsonrpc?tag=v8.0.1)",
+ "jsonrpc-core 8.0.2 (git+https://github.com/paritytech/jsonrpc)",
+ "jsonrpc-macros 8.0.1 (git+https://github.com/paritytech/jsonrpc)",
"lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1534,15 +1663,18 @@ dependencies = [
"assert_matches 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"env_logger 0.5.12 (registry+https://github.com/rust-lang/crates.io-index)",
"error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "jsonrpc-core 8.0.1 (git+https://github.com/paritytech/jsonrpc?tag=v8.0.1)",
- "jsonrpc-macros 8.0.0 (git+https://github.com/paritytech/jsonrpc?tag=v8.0.1)",
- "jsonrpc-pubsub 8.0.0 (git+https://github.com/paritytech/jsonrpc?tag=v8.0.1)",
- "jsonrpc-ws-server 8.0.0 (git+https://github.com/paritytech/jsonrpc?tag=v8.0.1)",
+ "futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)",
+ "jsonrpc-client-core 0.5.0 (git+https://github.com/mullvad/jsonrpc-client-rs)",
+ "jsonrpc-client-ipc 0.5.0 (git+https://github.com/mullvad/jsonrpc-client-rs)",
+ "jsonrpc-core 8.0.2 (git+https://github.com/paritytech/jsonrpc)",
+ "jsonrpc-ipc-server 8.0.1 (git+https://github.com/paritytech/jsonrpc)",
+ "jsonrpc-macros 8.0.1 (git+https://github.com/paritytech/jsonrpc)",
+ "jsonrpc-pubsub 8.0.1 (git+https://github.com/paritytech/jsonrpc)",
"log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.71 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)",
- "url 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "ws 0.7.5 (git+https://github.com/tomusdrw/ws-rs)",
+ "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)",
+ "uuid 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -1551,9 +1683,13 @@ version = "0.1.0"
dependencies = [
"env_logger 0.5.12 (registry+https://github.com/rust-lang/crates.io-index)",
"error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)",
+ "jsonrpc-client-core 0.5.0 (git+https://github.com/mullvad/jsonrpc-client-rs)",
+ "jsonrpc-client-ipc 0.5.0 (git+https://github.com/mullvad/jsonrpc-client-rs)",
"log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
"openvpn-plugin 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"talpid-ipc 0.1.0",
+ "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)",
"windres 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -1696,6 +1832,18 @@ dependencies = [
]
[[package]]
+name = "tokio-named-pipes"
+version = "0.1.0"
+source = "git+https://github.com/nikvolf/tokio-named-pipes?branch=stable#9a9372618552d2c25c2ee4511e5e0fb4eef318e3"
+dependencies = [
+ "bytes 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)",
+ "mio-named-pipes 0.1.6 (git+https://github.com/alexcrichton/mio-named-pipes)",
+ "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-io 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
name = "tokio-openssl"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1802,6 +1950,22 @@ dependencies = [
]
[[package]]
+name = "tokio-uds"
+version = "0.1.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "bytes 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)",
+ "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
+ "mio 0.6.15 (registry+https://github.com/rust-lang/crates.io-index)",
+ "mio-uds 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-io 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
name = "try-lock"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1820,19 +1984,6 @@ dependencies = [
]
[[package]]
-name = "unicode-bidi"
-version = "0.3.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "matches 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "unicode-normalization"
-version = "0.1.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
-[[package]]
name = "unicode-width"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1861,16 +2012,6 @@ dependencies = [
]
[[package]]
-name = "url"
-version = "1.7.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
- "matches 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
- "percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
name = "utf8-ranges"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2004,22 +2145,6 @@ dependencies = [
]
[[package]]
-name = "ws"
-version = "0.7.5"
-source = "git+https://github.com/tomusdrw/ws-rs#f12d19c4c19422fc79af28a3181f598bc07ecd1e"
-dependencies = [
- "byteorder 1.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
- "bytes 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)",
- "httparse 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
- "mio 0.6.15 (registry+https://github.com/rust-lang/crates.io-index)",
- "rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)",
- "sha1 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "url 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
name = "ws2_32-sys"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2088,24 +2213,27 @@ source = "git+https://github.com/mullvad/rust-openssl#4dbd237fe1f6454d8a0042ccf4
"checksum futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "ab90cde24b3319636588d0c35fe03b1333857621051837ed769faefb4c2162e4"
"checksum gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)" = "5e33ec290da0d127825013597dbdfc28bee4964690c7ce1166cbc2a7bd08b1bb"
"checksum globset 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "90d069fe6beb9be359ef505650b3f73228c5591a3c4b1f32be2f4f44459ffa3a"
+"checksum globset 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8e49edbcc9c7fc5beb8c0a54e7319ff8bed353a2b55e85811c6281188c2a6c84"
"checksum httparse 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7b6288d7db100340ca12873fd4d08ad1b8f206a9457798dfb17c018a33fee540"
"checksum humantime 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0484fda3e7007f2a4a0d9c3a703ca38c71c54c55602ce4660c419fd32e188c9e"
"checksum hyper 0.11.27 (registry+https://github.com/rust-lang/crates.io-index)" = "34a590ca09d341e94cddf8e5af0bbccde205d5fbc2fa3c09dd67c7f85cea59d7"
"checksum hyper-openssl 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0800c7b541e9b5be3e3cf8c8773d2fdb33975d07551fa1279d90e154c18db4d8"
-"checksum idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e"
"checksum inotify 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "887fcc180136e77a85e6a6128579a719027b1bab9b1c38ea4444244fe262c20c"
"checksum ioctl-sys 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5e2c4b26352496eaaa8ca7cfa9bd99e93419d3f7983dc6e99c2a35fe9e33504a"
"checksum iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dbe6e417e7d0975db6512b90796e8ce223145ac4e33c377e4a42882a0e88bb08"
"checksum ipnetwork 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b750b2f5cc97f86d0280a173e64fee0cbb4cb73077ee201208ff4f063668b89"
"checksum itoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5adb58558dcd1d786b5f0bd15f3226ee23486e24b7b58304b60f64dc68e62606"
+"checksum jsonrpc-client-core 0.5.0 (git+https://github.com/mullvad/jsonrpc-client-rs)" = "<none>"
"checksum jsonrpc-client-core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f29cb249837420fb0cee7fb0fbf1d22679e121b160e71bb5e0d90b9df241c23e"
"checksum jsonrpc-client-http 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2e642eb74423b9dfcb4512fda167148746b76f788a823cd712fadf409f31d302"
-"checksum jsonrpc-core 8.0.1 (git+https://github.com/paritytech/jsonrpc?tag=v8.0.1)" = "<none>"
+"checksum jsonrpc-client-ipc 0.5.0 (git+https://github.com/mullvad/jsonrpc-client-rs)" = "<none>"
"checksum jsonrpc-core 8.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ddf83704f4e79979a424d1082dd2c1e52683058056c9280efa19ac5f6bc9033c"
-"checksum jsonrpc-macros 8.0.0 (git+https://github.com/paritytech/jsonrpc?tag=v8.0.1)" = "<none>"
-"checksum jsonrpc-pubsub 8.0.0 (git+https://github.com/paritytech/jsonrpc?tag=v8.0.1)" = "<none>"
-"checksum jsonrpc-server-utils 8.0.0 (git+https://github.com/paritytech/jsonrpc?tag=v8.0.1)" = "<none>"
-"checksum jsonrpc-ws-server 8.0.0 (git+https://github.com/paritytech/jsonrpc?tag=v8.0.1)" = "<none>"
+"checksum jsonrpc-core 8.0.2 (git+https://github.com/paritytech/jsonrpc)" = "<none>"
+"checksum jsonrpc-ipc-server 8.0.1 (git+https://github.com/paritytech/jsonrpc)" = "<none>"
+"checksum jsonrpc-macros 8.0.1 (git+https://github.com/paritytech/jsonrpc)" = "<none>"
+"checksum jsonrpc-pubsub 8.0.1 (git+https://github.com/paritytech/jsonrpc)" = "<none>"
+"checksum jsonrpc-server-utils 8.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "513e981828a4953ea7ddbb64c24d15d4983ecf6900dc1cd36f257d61c27138d5"
+"checksum jsonrpc-server-utils 8.0.1 (git+https://github.com/paritytech/jsonrpc)" = "<none>"
"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
"checksum language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a"
"checksum lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca488b89a5657b0a2ecd45b95609b3e848cf1755da332a0da46e2b2b1cb371a7"
@@ -2113,18 +2241,21 @@ source = "git+https://github.com/mullvad/rust-openssl#4dbd237fe1f6454d8a0042ccf4
"checksum libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)" = "76e3a3ef172f1a0b9a9ff0dd1491ae5e6c948b94479a3021819ba7d860c8645d"
"checksum linked-hash-map 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "70fb39025bc7cdd76305867c4eccf2f2dcf6e9a57f5b21a93e1c2d86cd03ec9e"
"checksum linked_hash_set 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3c7c91c4c7bbeb4f2f7c4e5be11e6a05bd6830bc37249c47ce1ad86ad453ff9c"
+"checksum lock_api 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "949826a5ccf18c1b3a7c3d57692778d21768b79e46eb9dd07bfc4c2160036c54"
"checksum log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b"
"checksum log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "61bd98ae7f7b754bc53dca7d44b604f733c6bba044ea6f41bc8d89272d8161d2"
"checksum log-panics 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ae0136257df209261daa18d6c16394757c63e032e27aafd8b07788b051082bef"
-"checksum matches 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "835511bab37c34c47da5cb44844bea2cfde0236db0b506f90ea4224482c9774a"
"checksum memchr 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "148fab2e51b4f1cfc66da2a7c32981d1d3c083a803978268bb11fe4b86925e7a"
"checksum memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "796fba70e76612589ed2ce7f45282f5af869e0fdd7cc6199fa1aa1f1d591ba9d"
"checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3"
"checksum mime 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "fe51c8699d2dc522bf8c1ebe26ea2193d151fb54bcdfd7d0318750c189994cd9"
"checksum mio 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a637d1ca14eacae06296a008fa7ad955347e34efcb5891cfd8ba05491a37907e"
"checksum mio 0.6.15 (registry+https://github.com/rust-lang/crates.io-index)" = "4fcfcb32d63961fb6f367bfd5d21e4600b92cd310f71f9dca25acae196eb1560"
+"checksum mio-named-pipes 0.1.6 (git+https://github.com/alexcrichton/mio-named-pipes)" = "<none>"
+"checksum mio-uds 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "84c7b5caa3a118a6e34dbac36504503b1e8dc5835e833306b9d6af0e05929f79"
"checksum miow 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "3e690c5df6b2f60acd45d56378981e827ff8295562fc8d34f573deb267a59cd1"
"checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919"
+"checksum miow 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "396aa0f2003d7df8395cb93e09871561ccc3e785f0acb369170e8cc74ddf9226"
"checksum mnl 0.1.0 (git+https://github.com/mullvad/mnl-rs)" = "<none>"
"checksum mnl-sys 0.1.0 (git+https://github.com/mullvad/mnl-rs)" = "<none>"
"checksum net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "42550d9fb7b6684a6d404d9fa7250c2eb2646df731d1c06afc06dcee9e1bcf88"
@@ -2143,7 +2274,9 @@ source = "git+https://github.com/mullvad/rust-openssl#4dbd237fe1f6454d8a0042ccf4
"checksum os_pipe 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "fe033225d563042c3eeb22ffd1d2ea1aefcc48e7e37151a064c9e0bae64b253f"
"checksum os_pipe 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cd9d339267cdef39ee54ef165fdfaa2c7289a7465f0188ebe1c8a63872ca64c7"
"checksum owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cdf84f41639e037b484f93433aa3897863b561ed65c6e59c7073d7c561710f37"
-"checksum parking_lot 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "149d8f5b97f3c1133e3cfcd8886449959e856b557ff281e292b733d7c69e005e"
+"checksum parity-tokio-ipc 0.1.5 (git+https://github.com/NikVolf/parity-tokio-ipc?rev=stable)" = "<none>"
+"checksum parity-tokio-ipc 0.1.5 (git+https://github.com/nikvolf/parity-tokio-ipc?branch=stable)" = "<none>"
+"checksum parking_lot 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "69376b761943787ebd5cc85a5bc95958651a22609c5c1c2b65de21786baec72b"
"checksum parking_lot_core 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "4db1a8ccf734a7bce794cc19b3df06ed87ab2f3907036b693c68f56b4d4537fa"
"checksum percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831"
"checksum pfctl 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9aefb0dd38fc99f8bea821a69fa2cdeb57633bd80da078f2f7131d59ec4c91be"
@@ -2174,7 +2307,6 @@ source = "git+https://github.com/mullvad/rust-openssl#4dbd237fe1f6454d8a0042ccf4
"checksum serde 1.0.71 (registry+https://github.com/rust-lang/crates.io-index)" = "6dfad05c8854584e5f72fb859385ecdfa03af69c3fd0572f0da2d4c95f060bdb"
"checksum serde_derive 1.0.71 (registry+https://github.com/rust-lang/crates.io-index)" = "b719c6d5e9f73fbc37892246d5852333f040caa617b8873c6aced84bcb28e7bb"
"checksum serde_json 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)" = "c3c6908c7b925cd6c590358a4034de93dbddb20c45e1d021931459fd419bf0e2"
-"checksum sha1 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cc30b1e1e8c40c121ca33b86c23308a090d19974ef001b4bf6e61fd1a0fb095c"
"checksum shared_child 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7e254d79655b3a1cb86b4079fc080c91664af57d0a81facb59fc828503cd4f48"
"checksum shell-escape 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "170a13e64f2a51b77a45702ba77287f5c6829375b04a69cf2222acd17d0cfab9"
"checksum simple-signal 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "53f7da44adcc42667d57483bd93f81295f27d66897804b757573b61b6f13288b"
@@ -2184,6 +2316,7 @@ source = "git+https://github.com/mullvad/rust-openssl#4dbd237fe1f6454d8a0042ccf4
"checksum smallvec 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4c8cbcd6df1e117c2210e13ab5109635ad68a929fcbb8964dc965b76cb5ee013"
"checksum smallvec 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "211a489e65e94b103926d2054ae515a1cdb5d515ea0ef414fee23b7e043ce748"
"checksum snailquote 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "abe8023ba7352ceed1705c51d96f503c34eaec3142fa60e0591dce0fb3f81e03"
+"checksum socket2 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "962a516af4d3a7c272cb3a1d50a8cc4e5b41802e4ad54cfb7bee8ba61d37d703"
"checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8"
"checksum strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550"
"checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad"
@@ -2205,6 +2338,7 @@ source = "git+https://github.com/mullvad/rust-openssl#4dbd237fe1f6454d8a0042ccf4
"checksum tokio-executor 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "424f0c87ecd66b863045d84e384cb7ce0ae384d8b065b9f0363d29c0d1b30b2f"
"checksum tokio-fs 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b5cbe4ca6e71cb0b62a66e4e6f53a8c06a6eefe46cc5f665ad6f274c9906f135"
"checksum tokio-io 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "a5c9635ee806f26d302b8baa1e145689a280d8f5aa8d0552e7344808da54cc21"
+"checksum tokio-named-pipes 0.1.0 (git+https://github.com/nikvolf/tokio-named-pipes?branch=stable)" = "<none>"
"checksum tokio-openssl 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4646ae1fd623393de3d796ea53af75acd02938dd5579544fbd6d236d041978a6"
"checksum tokio-proto 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8fbb47ae81353c63c487030659494b295f6cb6576242f907f203473b191b0389"
"checksum tokio-reactor 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8703a5762ff6913510dc64272c714c4389ffd8c4b3cf602879b8bd14ff06b604"
@@ -2214,17 +2348,15 @@ source = "git+https://github.com/mullvad/rust-openssl#4dbd237fe1f6454d8a0042ccf4
"checksum tokio-timer 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6131e780037787ff1b3f8aad9da83bca02438b72277850dd6ad0d455e0e20efc"
"checksum tokio-timer 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "1c76b4e97a4f61030edff8bd272364e4f731b9f54c7307eb4eb733c3926eb96a"
"checksum tokio-udp 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "43eb534af6e8f37d43ab1b612660df14755c42bd003c5f8d2475ee78cc4600c0"
+"checksum tokio-uds 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "65ae5d255ce739e8537221ed2942e0445f4b3b813daebac1c0050ddaaa3587f9"
"checksum try-lock 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee2aa4715743892880f70885373966c83d73ef1b0838a664ef0c76fffd35e7c2"
"checksum ucd-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fd2be2d6639d0f8fe6cdda291ad456e23629558d466e2789d2c3e9892bda285d"
"checksum unicase 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "284b6d3db520d67fbe88fd778c21510d1b0ba4a551e5d0fbb023d33405f6de8a"
-"checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5"
-"checksum unicode-normalization 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "6a0180bc61fc5a987082bfa111f4cc95c4caff7f9799f3e46df09163a937aa25"
"checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526"
"checksum unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f860d7d29cf02cb2f3f359fd35991af3d30bac52c57d265a3c461074cb4dc"
"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
"checksum unicode_categories 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e"
"checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56"
-"checksum url 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2a321979c09843d272956e73700d12c4e7d3d92b2ee112b31548aef0d4efc5a6"
"checksum utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "662fab6525a98beff2921d7f61a39e7d59e0b425ebc7d0d9e66d316e55124122"
"checksum uuid 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e1436e58182935dcd9ce0add9ea0b558e8a87befe01c1a301e6020aeb0876363"
"checksum vcpkg 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "cbe533e138811704c0e3cbde65a818b35d3240409b4346256c5ede403e082474"
@@ -2244,5 +2376,4 @@ source = "git+https://github.com/mullvad/rust-openssl#4dbd237fe1f6454d8a0042ccf4
"checksum windows-service 0.1.0 (git+https://github.com/mullvad/windows-service-rs.git?rev=55c5dfb372e6b3f5607a3159c5388d27b6b84ff6)" = "<none>"
"checksum windres 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dd6e13ff705d7fab032bdf857354035c56c8c889e364029e4300779eb6e1d729"
"checksum winreg 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a27a759395c1195c4cc5cda607ef6f8f6498f64e78f7900f5de0a127a424704a"
-"checksum ws 0.7.5 (git+https://github.com/tomusdrw/ws-rs)" = "<none>"
"checksum ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e"
diff --git a/README.md b/README.md
index d6f9ac0e45..f59824b1b0 100644
--- a/README.md
+++ b/README.md
@@ -311,14 +311,14 @@ The cache directory can be changed by setting the `MULLVAD_CACHE_DIR` environmen
#### RPC address file
-The full path to the RPC address file can be changed by setting the `MULLVAD_RPC_ADDRESS_PATH`
+The full path to the RPC address file can be changed by setting the `MULLVAD_RPC_SOCKET_PATH`
environment variable.
| Platform | Path |
|----------|------|
-| Linux | `/tmp/.mullvad_rpc_address` |
-| macOS | `/tmp/.mullvad_rpc_address` |
-| Windows | `C:\ProgramData\Mullvad VPN\.mullvad_rpc_address` |
+| Linux | `/var/run/mullvad-vpn` |
+| macOS | `/var/run/mullvad-vpn` |
+| Windows | `//./pipe/Mullvad VPN` |
## Quirks
diff --git a/gui/packages/desktop/package.json b/gui/packages/desktop/package.json
index 98b6ab3c85..70ef5cc11c 100644
--- a/gui/packages/desktop/package.json
+++ b/gui/packages/desktop/package.json
@@ -13,6 +13,7 @@
"license": "GPL-3.0",
"dependencies": {
"@mullvad/components": "0.1.0",
+ "JSONStream": "^1.3.4",
"babel-runtime": "^6.26.0",
"connected-react-router": "^4.3.0",
"d3-geo-projection": "^2.3.2",
@@ -33,8 +34,7 @@
"validated": "^1.3.0"
},
"optionalDependencies": {
- "nseventmonitor": "https://github.com/mullvad/NSEventMonitor.git#0.0.9",
- "windows-security": "https://github.com/mullvad/windows-security.git#0.0.5"
+ "nseventmonitor": "https://github.com/mullvad/NSEventMonitor.git#0.0.9"
},
"devDependencies": {
"babel-cli": "^6.26.0",
diff --git a/gui/packages/desktop/src/common/types.js b/gui/packages/desktop/src/common/types.js
deleted file mode 100644
index f9ede46014..0000000000
--- a/gui/packages/desktop/src/common/types.js
+++ /dev/null
@@ -1,6 +0,0 @@
-// @flow
-
-export type RpcCredentials = {
- connectionString: string,
- sharedSecret: string,
-};
diff --git a/gui/packages/desktop/src/main/index.js b/gui/packages/desktop/src/main/index.js
index 34eb88247a..c9067a0146 100644
--- a/gui/packages/desktop/src/main/index.js
+++ b/gui/packages/desktop/src/main/index.js
@@ -10,7 +10,6 @@ import { app, screen, BrowserWindow, ipcMain, Tray, Menu, nativeImage } from 'el
import TrayIconController from './tray-icon-controller';
import WindowController from './window-controller';
-import RpcAddressFile from './rpc-address-file';
import ShutdownCoordinator from './shutdown-coordinator';
import { resolveBin } from './proc';
@@ -191,45 +190,6 @@ const ApplicationMain = {
},
_registerIpcListeners() {
- ipcMain.on('discover-daemon-connection', async (event) => {
- const addressFile = new RpcAddressFile();
-
- log.debug(`Waiting for RPC address file: "${addressFile.filePath}"`);
-
- try {
- await addressFile.waitUntilExists();
- } catch (error) {
- log.error(`Cannot finish polling the RPC address file: ${error.message}`);
- return;
- }
-
- try {
- if (!addressFile.isTrusted()) {
- log.error(`Cannot verify the credibility of RPC address file`);
- return;
- }
- } catch (error) {
- log.error(`An error occurred during the credibility check: ${error.message}`);
- return;
- }
-
- // There is a race condition here where the owner and permissions of
- // the file can change in the time between we validate the owner and
- // permissions and read the contents of the file. We deem the chance
- // of that to be small enough to ignore.
-
- try {
- const credentials = await addressFile.parse();
-
- log.debug('Read RPC connection info', credentials.connectionString);
-
- event.sender.send('daemon-connection-ready', credentials);
- } catch (error) {
- log.error(`Cannot parse the RPC address file: ${error.message}`);
- return;
- }
- });
-
ipcMain.on('show-window', () => {
const windowController = this._windowController;
if (windowController) {
diff --git a/gui/packages/desktop/src/main/rpc-address-file.js b/gui/packages/desktop/src/main/rpc-address-file.js
deleted file mode 100644
index 9c46165058..0000000000
--- a/gui/packages/desktop/src/main/rpc-address-file.js
+++ /dev/null
@@ -1,112 +0,0 @@
-// @flow
-
-import fs from 'fs';
-import path from 'path';
-import { app } from 'electron';
-import { promisify } from 'util';
-import { getSystemTemporaryDirectory } from './tempdir';
-
-import type { RpcCredentials } from '../common/types';
-
-const fsReadFileAsync = promisify(fs.readFile);
-
-const POLL_INTERVAL = 200;
-
-export default class RpcAddressFile {
- _filePath = getRpcAddressFilePath();
- _pollIntervalId: ?IntervalID;
- _pollPromise: ?Promise<void>;
-
- get filePath(): string {
- return this._filePath;
- }
-
- waitUntilExists(): Promise<void> {
- let promise = this._pollPromise;
-
- if (!promise) {
- promise = new Promise((resolve) => {
- const timer = setInterval(() => {
- fs.exists(this._filePath, (exists) => {
- if (exists) {
- clearInterval(timer);
- resolve();
-
- this._pollPromise = null;
- }
- });
- }, POLL_INTERVAL);
- });
-
- this._pollPromise = promise;
- }
-
- return promise;
- }
-
- async parse(): Promise<RpcCredentials> {
- const data = await fsReadFileAsync(this._filePath, 'utf8');
- const [connectionString, sharedSecret] = data.split('\n', 2);
-
- if (connectionString && sharedSecret !== undefined) {
- return {
- connectionString,
- sharedSecret,
- };
- } else {
- throw new Error('Cannot parse the RPC address file');
- }
- }
-
- isTrusted() {
- const filePath = this._filePath;
- switch (process.platform) {
- case 'win32':
- return isOwnedByLocalSystem(filePath);
- case 'darwin':
- case 'linux':
- return isOwnedAndOnlyWritableByRoot(filePath);
- default:
- throw new Error(`Unknown platform: ${process.platform}`);
- }
- }
-}
-
-function getRpcAddressFilePath() {
- const rpcAddressFileName = '.mullvad_rpc_address';
-
- switch (process.platform) {
- case 'win32': {
- // Windows: %ALLUSERSPROFILE%\{appname}
- const programDataDirectory = process.env.ALLUSERSPROFILE;
- if (programDataDirectory) {
- const appDataDirectory = path.join(programDataDirectory, app.getName());
- return path.join(appDataDirectory, rpcAddressFileName);
- } else {
- throw new Error('Missing %ALLUSERSPROFILE% environment variable');
- }
- }
- default:
- return path.join(getSystemTemporaryDirectory(), rpcAddressFileName);
- }
-}
-
-function isOwnedAndOnlyWritableByRoot(path: string): boolean {
- const stat = fs.statSync(path);
- const isOwnedByRoot = stat.uid === 0;
- const isOnlyWritableByOwner = (stat.mode & parseInt('022', 8)) === 0;
-
- return isOwnedByRoot && isOnlyWritableByOwner;
-}
-
-function isOwnedByLocalSystem(path: string): boolean {
- // $FlowFixMe: this module is only available on Windows
- const winsec = require('windows-security');
- const ownerSid = winsec.getFileOwnerSid(path, null);
- const isWellKnownSid = winsec.isWellKnownSid(
- ownerSid,
- winsec.WellKnownSid.BuiltinAdministratorsSid,
- );
-
- return isWellKnownSid;
-}
diff --git a/gui/packages/desktop/src/main/tempdir.js b/gui/packages/desktop/src/main/tempdir.js
deleted file mode 100644
index 938448949a..0000000000
--- a/gui/packages/desktop/src/main/tempdir.js
+++ /dev/null
@@ -1,20 +0,0 @@
-// @flow
-import path from 'path';
-
-export function getSystemTemporaryDirectory() {
- switch (process.platform) {
- case 'win32': {
- const windowsPath = process.env.windir;
- if (windowsPath) {
- return path.join(windowsPath, 'Temp');
- } else {
- throw new Error('Missing windir in environment variables.');
- }
- }
- case 'darwin':
- case 'linux':
- return '/tmp';
- default:
- throw new Error(`Not implemented for ${process.platform}`);
- }
-}
diff --git a/gui/packages/desktop/src/renderer/app.js b/gui/packages/desktop/src/renderer/app.js
index ad886f963c..e0374f05d5 100644
--- a/gui/packages/desktop/src/renderer/app.js
+++ b/gui/packages/desktop/src/renderer/app.js
@@ -26,7 +26,6 @@ import settingsActions from './redux/settings/actions';
import versionActions from './redux/version/actions';
import daemonActions from './redux/daemon/actions';
-import type { RpcCredentials } from '../common/types';
import type {
DaemonRpcProtocol,
AccountData,
@@ -41,7 +40,6 @@ export default class AppRenderer {
_notificationController = new NotificationController();
_daemonRpc: DaemonRpcProtocol = new DaemonRpc();
_reconnectBackoff = new ReconnectionBackoff();
- _credentials: ?RpcCredentials;
_openConnectionObserver: ?DaemonConnectionObserver;
_closeConnectionObserver: ?DaemonConnectionObserver;
_memoryHistory = createMemoryHistory();
@@ -418,16 +416,7 @@ export default class AppRenderer {
}
async _connectToDaemon(): Promise<void> {
- let credentials;
- try {
- credentials = await this._requestCredentials();
- } catch (error) {
- log.error(`Cannot request the RPC credentials: ${error.message}`);
- return;
- }
-
- this._credentials = credentials;
- this._daemonRpc.connect(credentials.connectionString);
+ this._daemonRpc.connect({ path: getIpcPath() });
}
async _onOpenConnection() {
@@ -437,17 +426,6 @@ export default class AppRenderer {
// reset the reconnect backoff when connection established.
this._reconnectBackoff.reset();
- // authenticate once connected
- const credentials = this._credentials;
- try {
- if (!credentials) {
- throw new Error('Credentials cannot be unset after connection is established.');
- }
- await this._authenticate(credentials.sharedSecret);
- } catch (error) {
- log.error(`Cannot authenticate: ${error.message}`);
- }
-
// attempt to restore the session
try {
await this._restoreSession();
@@ -508,15 +486,6 @@ export default class AppRenderer {
}
}
- _requestCredentials(): Promise<RpcCredentials> {
- return new Promise((resolve) => {
- ipcRenderer.once('daemon-connection-ready', (_event, credentials: RpcCredentials) => {
- resolve(credentials);
- });
- ipcRenderer.send('discover-daemon-connection');
- });
- }
-
async _subscribeStateListener() {
await this._daemonRpc.subscribeStateListener((newState, error) => {
if (error) {
@@ -655,3 +624,11 @@ class AccountDataState {
}
}
}
+
+const getIpcPath = (): string => {
+ if (process.platform === 'win32') {
+ return '//./pipe/Mullvad VPN';
+ } else {
+ return '/var/run/mullvad-vpn';
+ }
+};
diff --git a/gui/packages/desktop/src/renderer/lib/daemon-rpc.js b/gui/packages/desktop/src/renderer/lib/daemon-rpc.js
index 3f3d3af9c1..c403e3fa92 100644
--- a/gui/packages/desktop/src/renderer/lib/daemon-rpc.js
+++ b/gui/packages/desktop/src/renderer/lib/daemon-rpc.js
@@ -1,9 +1,10 @@
// @flow
-import JsonRpcTransport, {
+import JsonRpcClient, {
RemoteError as JsonRpcRemoteError,
TimeOutError as JsonRpcTimeOutError,
-} from './jsonrpc-transport';
+ SocketTransport,
+} from './jsonrpc-client';
import { CommunicationError, InvalidAccountError, NoDaemonError } from '../errors';
import {
@@ -222,7 +223,7 @@ const AppVersionInfoSchema = object({
});
export interface DaemonRpcProtocol {
- connect(string): void;
+ connect({ path: string }): void;
disconnect(): void;
getAccountData(AccountToken): Promise<AccountData>;
getRelayLocations(): Promise<RelayList>;
@@ -268,14 +269,14 @@ export type ConnectionObserver = {
};
export class DaemonRpc implements DaemonRpcProtocol {
- _transport = new JsonRpcTransport();
+ _transport = new JsonRpcClient(new SocketTransport());
async authenticate(sharedSecret: string): Promise<void> {
await this._transport.send('auth', sharedSecret);
}
- connect(connectionString: string) {
- this._transport.connect(connectionString);
+ connect(connectionParams: { path: string }) {
+ this._transport.connect(connectionParams);
}
disconnect() {
diff --git a/gui/packages/desktop/src/renderer/lib/jsonrpc-transport.js b/gui/packages/desktop/src/renderer/lib/jsonrpc-client.js
index e5c81e6b0f..cf779c83be 100644
--- a/gui/packages/desktop/src/renderer/lib/jsonrpc-transport.js
+++ b/gui/packages/desktop/src/renderer/lib/jsonrpc-client.js
@@ -4,6 +4,8 @@ import { EventEmitter } from 'events';
import log from 'electron-log';
import jsonrpc from 'jsonrpc-lite';
import uuid from 'uuid';
+import net from 'net';
+import JSONStream from 'JSONStream';
export type UnansweredRequest = {
resolve: (mixed) => void,
@@ -90,11 +92,11 @@ export class SubscriptionError extends Error {
}
}
-export class ConnectionError extends Error {
+export class WebSocketError extends Error {
_code: number;
constructor(code: number) {
- super(ConnectionError.reason(code));
+ super(WebSocketError.reason(code));
this._code = code;
}
@@ -118,34 +120,39 @@ export class ConnectionError extends Error {
}
}
+export class TransportError extends Error {
+ constructor(reason: string) {
+ super(reason);
+ }
+}
+
const DEFAULT_TIMEOUT_MILLIS = 5000;
-export default class JsonRpcTransport extends EventEmitter {
+export default class JsonRpcClient<T> extends EventEmitter {
_unansweredRequests: Map<string, UnansweredRequest> = new Map();
_subscriptions: Map<string | number, (mixed) => void> = new Map();
- _webSocket: ?WebSocket;
- _websocketFactory: (string) => WebSocket;
+ _transport: Transport<T>;
- constructor(websocketFactory: ?(string) => WebSocket) {
+ constructor(transport: Transport<T>) {
super();
- this._websocketFactory =
- websocketFactory || ((connectionString) => new WebSocket(connectionString));
+
+ this._transport = transport;
}
/// Connect websocket
- connect(connectionString: string): Promise<void> {
+ connect(connectionParams: T): Promise<void> {
return new Promise((resolve, reject) => {
this.disconnect();
- log.info('Connecting to websocket', connectionString);
-
- const webSocket = this._websocketFactory(connectionString);
+ log.info('Connecting to transport with params', connectionParams);
// A flag used to determine if Promise was resolved.
let isPromiseResolved = false;
- webSocket.onopen = () => {
- log.info('Websocket is connected');
+ const transport = this._transport;
+
+ transport.onOpen = () => {
+ log.info('Transport is connected');
this.emit('open');
// Resolve the Promise
@@ -153,40 +160,30 @@ export default class JsonRpcTransport extends EventEmitter {
isPromiseResolved = true;
};
- webSocket.onmessage = (event) => {
- const data = event.data;
- if (typeof data === 'string') {
- this._onMessage(data);
- } else {
- log.error('Got invalid reply from the server', event);
- }
+ transport.onMessage = (obj) => {
+ this._onMessage(obj);
};
- webSocket.onclose = (event) => {
- log.info(`The websocket connection closed with code: ${event.code}`);
-
+ transport.onClose = (error: ?Error) => {
// Remove all subscriptions since they are connection based
this._subscriptions.clear();
- // 1000 is a code used for normal connection closure.
- const connectionError = event.code === 1000 ? null : new ConnectionError(event.code);
-
- this.emit('close', connectionError);
+ this.emit('close', error);
// Prevent rejecting a previously resolved Promise.
if (!isPromiseResolved) {
- reject(connectionError);
+ reject(error);
}
};
+ transport.connect(connectionParams);
- this._webSocket = webSocket;
+ this._transport = transport;
});
}
disconnect() {
- if (this._webSocket) {
- this._webSocket.close();
- this._webSocket = null;
+ if (this._transport) {
+ this._transport.close();
}
}
@@ -211,8 +208,8 @@ export default class JsonRpcTransport extends EventEmitter {
send(action: string, data: mixed, timeout: number = DEFAULT_TIMEOUT_MILLIS): Promise<mixed> {
return new Promise((resolve, reject) => {
- const webSocket = this._webSocket;
- if (!webSocket) {
+ const transport = this._transport;
+ if (!transport) {
reject(new Error('Websocket is not connected.'));
return;
}
@@ -230,7 +227,7 @@ export default class JsonRpcTransport extends EventEmitter {
try {
log.silly('Sending message', id, action);
- webSocket.send(JSON.stringify(message));
+ transport.send(JSON.stringify(message));
} catch (error) {
log.error(`Failed sending RPC message "${action}": ${error.message}`);
@@ -272,9 +269,14 @@ export default class JsonRpcTransport extends EventEmitter {
}
}
- _onMessage(message: string) {
- const result = jsonrpc.parse(message);
- const messages = Array.isArray(result) ? result : [result];
+ _onMessage(obj: Object) {
+ let messages = [];
+ try {
+ const message = jsonrpc.parseObject(obj);
+ messages = Array.isArray(message) ? message : [message];
+ } catch (error) {
+ log.error(`Failed to parse JSON-RPC message: ${error} for object`);
+ }
for (const message of messages) {
if (message.type === 'notification') {
@@ -319,3 +321,128 @@ export default class JsonRpcTransport extends EventEmitter {
}
}
}
+
+interface Transport<T> {
+ close(): void;
+ onOpen: (event: Event) => void;
+ onMessage: (Object) => void;
+ onClose: (error: ?Error) => void;
+ send(message: string): void;
+ connect(params: T): void;
+}
+
+export class WebsocketTransport implements Transport<string> {
+ ws: ?WebSocket;
+ onOpen: (event: Event) => void;
+ onMessage: (Object) => void;
+ onClose: (error: ?Error) => void;
+
+ constructor(ws: ?WebSocket) {
+ this.ws = ws;
+ this.onOpen = () => {};
+ this.onMessage = () => {};
+ this.onClose = () => {};
+ }
+
+ close() {
+ if (this.ws) this.ws.close();
+ }
+
+ send(msg: string) {
+ if (this.ws) {
+ this.ws.send(msg);
+ }
+ }
+
+ connect(params: string): void {
+ if (this.ws) {
+ this.ws.close();
+ }
+ this.ws = new WebSocket(params);
+ this.ws.onopen = this.onOpen;
+ this.ws.onmessage = (event) => {
+ try {
+ const data = event.data;
+ if (typeof data === 'string') {
+ const msg = JSON.parse(data);
+ this.onMessage(msg);
+ } else {
+ throw event;
+ }
+ } catch (error) {
+ log.error('Got invalid reply from server: ', error);
+ }
+ };
+
+ this.ws.onclose = (event) => {
+ log.info(`The websocket connection closed with code: ${event.code}`);
+ const error = event.code === 1000 ? null : new WebSocketError(event.code);
+ this.onClose(error);
+ };
+ }
+}
+
+// Given the correct parameters, this transport supports named pipes/unix
+// domain sockets, and also TCP/UDP sockets
+export class SocketTransport implements Transport<{ path: string }> {
+ connection: ?net.Socket;
+ onMessage: (message: Object) => void;
+ onClose: (error: ?Error) => void;
+ onOpen: (event: Event) => void;
+
+ constructor() {
+ this.connection = null;
+ this.onMessage = () => {};
+ this.onClose = () => {};
+ this.onOpen = () => {};
+ }
+
+ _connect(options: { path: string }) {
+ const connection = new net.Socket();
+ connection.on('error', (err) => {
+ this.onClose(err);
+ this.close();
+ });
+
+ connection.on('connect', (event) => {
+ this.connection = connection;
+ this.onOpen(event);
+ });
+
+ const jsonStream = JSONStream.parse();
+
+ connection.pipe(jsonStream);
+
+ jsonStream.on('data', this.onMessage);
+
+ jsonStream.on('error', (err) => {
+ this.onClose(err);
+ this.close();
+ });
+
+ connection.connect(options);
+ }
+
+ close() {
+ try {
+ if (this.connection) {
+ this.connection.end();
+ }
+ } catch (error) {
+ log.error('failed to close the connection: ', error);
+ }
+ this.connection = null;
+ }
+
+ send(msg: string) {
+ if (this.connection) {
+ this.connection.write(msg);
+ } else {
+ throw new TransportError('Socket not connected');
+ }
+ }
+
+ connect(options: { path: string }): void {
+ this._connect(options);
+ }
+}
diff --git a/gui/packages/desktop/test/jsonrpc-transport.spec.js b/gui/packages/desktop/test/jsonrpc-transport.spec.js
index 5e600f2204..ea07e060b8 100644
--- a/gui/packages/desktop/test/jsonrpc-transport.spec.js
+++ b/gui/packages/desktop/test/jsonrpc-transport.spec.js
@@ -1,15 +1,18 @@
// @flow
import jsonrpc from 'jsonrpc-lite';
-import { Server, WebSocket as MockWebSocket } from 'mock-socket';
-import JsonRpcTransport, { TimeOutError } from '../src/renderer/lib/jsonrpc-transport';
+import { Server } from 'mock-socket';
+import JsonRpcClient, {
+ WebsocketTransport,
+ TimeOutError,
+} from '../src/renderer/lib/jsonrpc-client';
describe('JSON RPC transport', () => {
const WEBSOCKET_URL = 'ws://localhost:8080';
- let server: Server, transport: JsonRpcTransport;
+ let server: Server, transport: JsonRpcClient<string>;
beforeEach(() => {
server = new Server(WEBSOCKET_URL);
- transport = new JsonRpcTransport((url) => new MockWebSocket(url));
+ transport = new JsonRpcClient(new WebsocketTransport());
});
afterEach(() => {
diff --git a/gui/yarn.lock b/gui/yarn.lock
index cded790c63..102a3b710e 100644
--- a/gui/yarn.lock
+++ b/gui/yarn.lock
@@ -684,6 +684,13 @@
version "2.3.3"
resolved "https://registry.yarnpkg.com/@types/tough-cookie/-/tough-cookie-2.3.3.tgz#7f226d67d654ec9070e755f46daebf014628e9d9"
+JSONStream@^1.3.4:
+ version "1.3.4"
+ resolved "https://registry.yarnpkg.com/JSONStream/-/JSONStream-1.3.4.tgz#615bb2adb0cd34c8f4c447b5f6512fa1d8f16a2e"
+ dependencies:
+ jsonparse "^1.2.0"
+ through ">=2.2.7 <3"
+
abab@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.0.tgz#aba0ab4c5eee2d4c79d3487d85450fb2376ebb0f"
@@ -4625,6 +4632,10 @@ jsonify@~0.0.0:
version "0.0.0"
resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73"
+jsonparse@^1.2.0:
+ version "1.3.1"
+ resolved "https://registry.yarnpkg.com/jsonparse/-/jsonparse-1.3.1.tgz#3f4dae4a91fac315f71062f8521cc239f1366280"
+
jsonrpc-lite@^1.2.3:
version "1.3.1"
resolved "https://registry.yarnpkg.com/jsonrpc-lite/-/jsonrpc-lite-1.3.1.tgz#5c33086071793a0806e6c96e7c1ae92f4460ac50"
@@ -7251,7 +7262,7 @@ through2@~0.2.3:
readable-stream "~1.1.9"
xtend "~2.1.1"
-through@2, through@^2.3.6, through@^2.3.8, through@~2.3, through@~2.3.1:
+through@2, "through@>=2.2.7 <3", through@^2.3.6, through@^2.3.8, through@~2.3, through@~2.3.1:
version "2.3.8"
resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5"
@@ -7728,12 +7739,6 @@ window-size@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.2.0.tgz#b4315bb4214a3d7058ebeee892e13fa24d98b075"
-"windows-security@https://github.com/mullvad/windows-security.git#0.0.5":
- version "0.0.5"
- resolved "https://github.com/mullvad/windows-security.git#311fcfeb137e9e10b25929b0615f9188e118004f"
- dependencies:
- node-pre-gyp "^0.10.0"
-
wordwrap@^1.0.0, wordwrap@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb"
diff --git a/mullvad-cli/Cargo.toml b/mullvad-cli/Cargo.toml
index 7f9b39d92e..744a0aa2aa 100644
--- a/mullvad-cli/Cargo.toml
+++ b/mullvad-cli/Cargo.toml
@@ -14,9 +14,11 @@ clap = "2.20"
error-chain = "0.12"
env_logger = "0.5"
serde = "1.0"
+futures = "0.1"
mullvad-ipc-client = { path = "../mullvad-ipc-client" }
mullvad-types = { path = "../mullvad-types" }
+mullvad-paths = { path = "../mullvad-paths" }
talpid-types = { path = "../talpid-types" }
talpid-ipc = { path = "../talpid-ipc" }
diff --git a/mullvad-cli/src/cmds/account.rs b/mullvad-cli/src/cmds/account.rs
index 5757aac42d..bab9f525f6 100644
--- a/mullvad-cli/src/cmds/account.rs
+++ b/mullvad-cli/src/cmds/account.rs
@@ -1,7 +1,6 @@
use clap;
-use {Command, Result};
+use {new_rpc_client, Command, Result};
-use mullvad_ipc_client::DaemonRpcClient;
use mullvad_types::account::AccountToken;
pub struct Account;
@@ -48,7 +47,7 @@ impl Command for Account {
impl Account {
fn set(&self, token: Option<AccountToken>) -> Result<()> {
- let mut rpc = DaemonRpcClient::new()?;
+ let mut rpc = new_rpc_client()?;
rpc.set_account(token.clone())?;
if let Some(token) = token {
println!("Mullvad account \"{}\" set", token);
@@ -59,7 +58,7 @@ impl Account {
}
fn get(&self) -> Result<()> {
- let mut rpc = DaemonRpcClient::new()?;
+ let mut rpc = new_rpc_client()?;
let account_token = rpc.get_account()?;
if let Some(account_token) = account_token {
println!("Mullvad account: {}", account_token);
diff --git a/mullvad-cli/src/cmds/auto_connect.rs b/mullvad-cli/src/cmds/auto_connect.rs
index f471fbde56..5061f67fb8 100644
--- a/mullvad-cli/src/cmds/auto_connect.rs
+++ b/mullvad-cli/src/cmds/auto_connect.rs
@@ -1,8 +1,7 @@
use clap;
+use new_rpc_client;
use {Command, Result};
-use mullvad_ipc_client::DaemonRpcClient;
-
pub struct AutoConnect;
impl Command for AutoConnect {
@@ -42,14 +41,14 @@ impl Command for AutoConnect {
impl AutoConnect {
fn set(&self, auto_connect: bool) -> Result<()> {
- let mut rpc = DaemonRpcClient::new()?;
+ let mut rpc = new_rpc_client()?;
rpc.set_auto_connect(auto_connect)?;
println!("Changed auto-connect sharing setting");
Ok(())
}
fn get(&self) -> Result<()> {
- let mut rpc = DaemonRpcClient::new()?;
+ let mut rpc = new_rpc_client()?;
let auto_connect = rpc.get_auto_connect()?;
println!("Autoconnect: {}", if auto_connect { "on" } else { "off" });
Ok(())
diff --git a/mullvad-cli/src/cmds/connect.rs b/mullvad-cli/src/cmds/connect.rs
index b9da45618d..b7cf7cd8c5 100644
--- a/mullvad-cli/src/cmds/connect.rs
+++ b/mullvad-cli/src/cmds/connect.rs
@@ -1,8 +1,8 @@
use clap;
+use new_rpc_client;
use Command;
use Result;
-use mullvad_ipc_client::DaemonRpcClient;
pub struct Connect;
@@ -17,7 +17,7 @@ impl Command for Connect {
}
fn run(&self, _matches: &clap::ArgMatches) -> Result<()> {
- let mut rpc = DaemonRpcClient::new()?;
+ let mut rpc = new_rpc_client()?;
rpc.connect()?;
Ok(())
}
diff --git a/mullvad-cli/src/cmds/disconnect.rs b/mullvad-cli/src/cmds/disconnect.rs
index 70e5699545..99009d705f 100644
--- a/mullvad-cli/src/cmds/disconnect.rs
+++ b/mullvad-cli/src/cmds/disconnect.rs
@@ -1,8 +1,8 @@
use clap;
+use new_rpc_client;
use Command;
use Result;
-use mullvad_ipc_client::DaemonRpcClient;
pub struct Disconnect;
@@ -17,7 +17,7 @@ impl Command for Disconnect {
}
fn run(&self, _matches: &clap::ArgMatches) -> Result<()> {
- let mut rpc = DaemonRpcClient::new()?;
+ let mut rpc = new_rpc_client()?;
rpc.disconnect()?;
Ok(())
}
diff --git a/mullvad-cli/src/cmds/lan.rs b/mullvad-cli/src/cmds/lan.rs
index bd6516f6bf..65754e3425 100644
--- a/mullvad-cli/src/cmds/lan.rs
+++ b/mullvad-cli/src/cmds/lan.rs
@@ -1,7 +1,5 @@
use clap;
-use {Command, Result};
-
-use mullvad_ipc_client::DaemonRpcClient;
+use {new_rpc_client, Command, Result};
pub struct Lan;
@@ -42,14 +40,14 @@ impl Command for Lan {
impl Lan {
fn set(&self, allow_lan: bool) -> Result<()> {
- let mut rpc = DaemonRpcClient::new()?;
+ let mut rpc = new_rpc_client()?;
rpc.set_allow_lan(allow_lan)?;
println!("Changed local network sharing setting");
Ok(())
}
fn get(&self) -> Result<()> {
- let mut rpc = DaemonRpcClient::new()?;
+ let mut rpc = new_rpc_client()?;
let allow_lan = rpc.get_allow_lan()?;
println!(
"Local network sharing setting: {}",
diff --git a/mullvad-cli/src/cmds/relay.rs b/mullvad-cli/src/cmds/relay.rs
index 5be05786cc..4de7571307 100644
--- a/mullvad-cli/src/cmds/relay.rs
+++ b/mullvad-cli/src/cmds/relay.rs
@@ -1,8 +1,7 @@
use clap;
use std::str::FromStr;
-use {Command, Result, ResultExt};
+use {new_rpc_client, Command, Result, ResultExt};
-use mullvad_ipc_client::DaemonRpcClient;
use mullvad_types::relay_constraints::{
Constraint, LocationConstraint, OpenVpnConstraints, RelayConstraintsUpdate,
RelaySettingsUpdate, TunnelConstraints,
@@ -101,7 +100,7 @@ impl Command for Relay {
impl Relay {
fn update_constraints(&self, update: RelaySettingsUpdate) -> Result<()> {
- let mut rpc = DaemonRpcClient::new()?;
+ let mut rpc = new_rpc_client()?;
rpc.update_relay_settings(update)?;
println!("Relay constraints updated");
Ok(())
@@ -171,7 +170,7 @@ impl Relay {
}
fn get(&self) -> Result<()> {
- let mut rpc = DaemonRpcClient::new()?;
+ let mut rpc = new_rpc_client()?;
let constraints = rpc.get_relay_settings()?;
println!("Current constraints: {:#?}", constraints);
@@ -179,7 +178,7 @@ impl Relay {
}
fn list(&self, _matches: &clap::ArgMatches) -> Result<()> {
- let mut rpc = DaemonRpcClient::new()?;
+ let mut rpc = new_rpc_client()?;
let mut locations = rpc.get_relay_locations()?;
locations.countries.sort_by(|c1, c2| c1.name.cmp(&c2.name));
for mut country in locations.countries {
diff --git a/mullvad-cli/src/cmds/status.rs b/mullvad-cli/src/cmds/status.rs
index 0b6b7f05ef..1a5a2b29e4 100644
--- a/mullvad-cli/src/cmds/status.rs
+++ b/mullvad-cli/src/cmds/status.rs
@@ -1,4 +1,5 @@
use clap;
+use new_rpc_client;
use Command;
use Result;
@@ -31,12 +32,11 @@ impl Command for Status {
}
fn run(&self, matches: &clap::ArgMatches) -> Result<()> {
- let mut rpc = DaemonRpcClient::new()?;
+ let mut rpc = new_rpc_client()?;
let state = rpc.get_state()?;
print_state(state);
print_location(&mut rpc)?;
-
if matches.subcommand_matches("listen").is_some() {
for new_state in rpc.new_state_subscribe()? {
print_state(new_state);
@@ -46,7 +46,6 @@ impl Command for Status {
}
}
}
-
Ok(())
}
}
diff --git a/mullvad-cli/src/cmds/tunnel.rs b/mullvad-cli/src/cmds/tunnel.rs
index a0c86fe1f0..f44a6b8cf5 100644
--- a/mullvad-cli/src/cmds/tunnel.rs
+++ b/mullvad-cli/src/cmds/tunnel.rs
@@ -1,7 +1,6 @@
use clap;
-use {Command, Result};
+use {new_rpc_client, Command, Result};
-use mullvad_ipc_client::DaemonRpcClient;
use talpid_types::net::{OpenVpnTunnelOptions, TunnelOptions};
pub struct Tunnel;
@@ -79,7 +78,7 @@ impl Tunnel {
fn set_openvpn_enable_ipv6_option(args: &clap::ArgMatches) -> Result<()> {
let enabled = args.value_of("enable").unwrap() == "on";
- let mut rpc = DaemonRpcClient::new()?;
+ let mut rpc = new_rpc_client()?;
rpc.set_openvpn_enable_ipv6(enabled)?;
println!("enable_ipv6 parameter updated");
Ok(())
@@ -93,14 +92,14 @@ impl Tunnel {
Some(mssfix_str.parse()?)
};
- let mut rpc = DaemonRpcClient::new()?;
+ let mut rpc = new_rpc_client()?;
rpc.set_openvpn_mssfix(mssfix)?;
println!("mssfix parameter updated");
Ok(())
}
fn get_tunnel_options() -> Result<TunnelOptions> {
- let mut rpc = DaemonRpcClient::new()?;
+ let mut rpc = new_rpc_client()?;
Ok(rpc.get_tunnel_options()?)
}
diff --git a/mullvad-cli/src/cmds/version.rs b/mullvad-cli/src/cmds/version.rs
index c3adca3040..2277e57d68 100644
--- a/mullvad-cli/src/cmds/version.rs
+++ b/mullvad-cli/src/cmds/version.rs
@@ -1,7 +1,5 @@
use clap;
-use {Command, Result};
-
-use mullvad_ipc_client::DaemonRpcClient;
+use {new_rpc_client, Command, Result};
pub struct Version;
@@ -16,7 +14,7 @@ impl Command for Version {
}
fn run(&self, _: &clap::ArgMatches) -> Result<()> {
- let mut rpc = DaemonRpcClient::new()?;
+ let mut rpc = new_rpc_client()?;
let current_version = rpc.get_current_version()?;
println!("Current version: {}", current_version);
let version_info = rpc.get_version_info()?;
diff --git a/mullvad-cli/src/main.rs b/mullvad-cli/src/main.rs
index 2c551c5622..0cf9e9307a 100644
--- a/mullvad-cli/src/main.rs
+++ b/mullvad-cli/src/main.rs
@@ -9,9 +9,11 @@
#[macro_use]
extern crate clap;
extern crate env_logger;
+extern crate futures;
#[macro_use]
extern crate error_chain;
extern crate mullvad_ipc_client;
+extern crate mullvad_paths;
extern crate mullvad_types;
extern crate serde;
extern crate talpid_types;
@@ -19,6 +21,7 @@ extern crate talpid_types;
mod cmds;
+use mullvad_ipc_client::{new_standalone_ipc_client, DaemonRpcClient};
use std::io;
error_chain! {
@@ -28,10 +31,14 @@ error_chain! {
}
links {
- RpcError(mullvad_ipc_client::Error, mullvad_ipc_client::ErrorKind);
+ RpcClientError(mullvad_ipc_client::Error, mullvad_ipc_client::ErrorKind);
}
}
+pub fn new_rpc_client() -> Result<DaemonRpcClient> {
+ new_standalone_ipc_client(&mullvad_paths::get_rpc_socket_path()).map_err(|e| Error::from(e))
+}
+
quick_main!(run);
fn run() -> Result<()> {
diff --git a/mullvad-daemon/Cargo.toml b/mullvad-daemon/Cargo.toml
index bd6add0daf..b6cd7a9884 100644
--- a/mullvad-daemon/Cargo.toml
+++ b/mullvad-daemon/Cargo.toml
@@ -15,10 +15,10 @@ serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
log = "0.4"
log-panics = "2.0.0"
-jsonrpc-core = { git = "https://github.com/paritytech/jsonrpc", tag = "v8.0.1" }
-jsonrpc-macros = { git = "https://github.com/paritytech/jsonrpc", tag = "v8.0.1" }
-jsonrpc-pubsub = { git = "https://github.com/paritytech/jsonrpc", tag = "v8.0.1" }
-jsonrpc-ws-server = { git = "https://github.com/paritytech/jsonrpc", tag = "v8.0.1" }
+jsonrpc-core = { git = "https://github.com/paritytech/jsonrpc", branch = "master" }
+jsonrpc-macros = { git = "https://github.com/paritytech/jsonrpc", branch = "master" }
+jsonrpc-pubsub = { git = "https://github.com/paritytech/jsonrpc", branch = "master" }
+jsonrpc-ipc-server = { git = "https://github.com/paritytech/jsonrpc", branch = "master" }
uuid = { version = "0.6", features = ["v4"] }
lazy_static = "1.0"
rand = "0.5"
diff --git a/mullvad-daemon/src/main.rs b/mullvad-daemon/src/main.rs
index 848207fbb1..373aca1715 100644
--- a/mullvad-daemon/src/main.rs
+++ b/mullvad-daemon/src/main.rs
@@ -25,8 +25,8 @@ extern crate serde_json;
extern crate jsonrpc_core;
#[macro_use]
extern crate jsonrpc_macros;
+extern crate jsonrpc_ipc_server;
extern crate jsonrpc_pubsub;
-extern crate jsonrpc_ws_server;
extern crate rand;
extern crate tokio_core;
extern crate tokio_timer;
@@ -50,7 +50,6 @@ mod geoip;
mod logging;
mod management_interface;
mod relays;
-mod rpc_address_file;
mod rpc_uniqueness_check;
mod settings;
mod shutdown;
@@ -126,7 +125,7 @@ pub enum DaemonEvent {
/// An event coming from the JSONRPC-2.0 management interface.
ManagementInterfaceEvent(ManagementCommand),
/// Triggered if the server hosting the JSONRPC-2.0 management interface dies unexpectedly.
- ManagementInterfaceExited(talpid_ipc::Result<()>),
+ ManagementInterfaceExited,
/// Daemon shutdown triggered by a signal, ctrl-c or similar.
TriggerShutdown,
}
@@ -286,18 +285,13 @@ impl Daemon {
event_tx: IntoSender<ManagementCommand, DaemonEvent>,
cache_dir: PathBuf,
) -> Result<ManagementInterfaceServer> {
- let shared_secret = uuid::Uuid::new_v4().to_string();
-
- let server = ManagementInterfaceServer::start(event_tx, shared_secret.clone(), cache_dir)
+ let server = ManagementInterfaceServer::start(event_tx, cache_dir)
.chain_err(|| ErrorKind::ManagementInterfaceError("Failed to start server"))?;
info!(
"Mullvad management interface listening on {}",
- server.address()
+ server.socket_path()
);
- rpc_address_file::write(server.address(), &shared_secret).chain_err(|| {
- ErrorKind::ManagementInterfaceError("Failed to write RPC connection info to file")
- })?;
Ok(server)
}
@@ -306,9 +300,9 @@ impl Daemon {
exit_tx: mpsc::Sender<DaemonEvent>,
) {
thread::spawn(move || {
- let result = server.wait();
+ server.wait();
error!("Mullvad management interface shut down");
- let _ = exit_tx.send(DaemonEvent::ManagementInterfaceExited(result));
+ let _ = exit_tx.send(DaemonEvent::ManagementInterfaceExited);
});
}
@@ -333,7 +327,7 @@ impl Daemon {
match event {
TunnelStateTransition(transition) => self.handle_tunnel_state_transition(transition),
ManagementInterfaceEvent(event) => self.handle_management_interface_event(event),
- ManagementInterfaceExited(result) => self.handle_management_interface_exited(result),
+ ManagementInterfaceExited => self.handle_management_interface_exited(),
TriggerShutdown => self.handle_trigger_shutdown_event(),
}
}
@@ -599,12 +593,8 @@ impl Daemon {
}
}
- fn handle_management_interface_exited(&self, result: talpid_ipc::Result<()>) -> Result<()> {
- let error = ErrorKind::ManagementInterfaceError("Server exited unexpectedly");
- match result {
- Ok(()) => Err(error.into()),
- Err(e) => Err(e).chain_err(|| error),
- }
+ fn handle_management_interface_exited(&self) -> Result<()> {
+ Err(ErrorKind::ManagementInterfaceError("Server exited unexpectedly").into())
}
fn handle_trigger_shutdown_event(&mut self) -> Result<()> {
@@ -721,10 +711,12 @@ impl DaemonShutdownHandle {
impl Drop for Daemon {
fn drop(self: &mut Daemon) {
- if let Err(e) =
- rpc_address_file::remove().chain_err(|| "Unable to clean up rpc address file")
+ #[cfg(unix)]
{
- error!("{}", e.display_chain());
+ use std::fs;
+ if let Err(e) = fs::remove_file(mullvad_paths::get_rpc_socket_path()) {
+ error!("Failed to remove RPC socket: {}", e);
+ }
}
}
}
diff --git a/mullvad-daemon/src/management_interface.rs b/mullvad-daemon/src/management_interface.rs
index 3f2d920180..4d7a509018 100644
--- a/mullvad-daemon/src/management_interface.rs
+++ b/mullvad-daemon/src/management_interface.rs
@@ -4,13 +4,14 @@ use error_chain::ChainedError;
use jsonrpc_core::futures::sync::oneshot::Sender as OneshotSender;
use jsonrpc_core::futures::{future, sync, Future};
use jsonrpc_core::{Error, ErrorCode, MetaIoHandler, Metadata};
+use jsonrpc_ipc_server;
use jsonrpc_macros::pubsub;
use jsonrpc_pubsub::{PubSubHandler, PubSubMetadata, Session, SubscriptionId};
-use jsonrpc_ws_server;
use mullvad_rpc;
use mullvad_types::account::{AccountData, AccountToken};
use mullvad_types::location::GeoIpLocation;
+use mullvad_paths;
use mullvad_types::relay_constraints::{RelaySettings, RelaySettingsUpdate};
use mullvad_types::relay_list::RelayList;
use mullvad_types::states::{DaemonState, TargetState};
@@ -21,7 +22,6 @@ use serde;
use std::collections::hash_map::Entry;
use std::collections::HashMap;
use std::path::PathBuf;
-use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{Arc, Mutex, RwLock};
use talpid_core::mpsc::IntoSender;
@@ -40,10 +40,6 @@ build_rpc_trait! {
pub trait ManagementInterfaceApi {
type Metadata;
- /// Authenticate the client towards this daemon instance. This method must be called once
- /// before any other call based on the same connection will work.
- #[rpc(meta, name = "auth")]
- fn auth(&self, Self::Metadata, String) -> BoxFuture<(), Error>;
/// Fetches and returns metadata about an account. Returns an error on non-existing
/// accounts.
@@ -225,27 +221,31 @@ pub struct ManagementInterfaceServer {
impl ManagementInterfaceServer {
pub fn start<T>(
tunnel_tx: IntoSender<ManagementCommand, T>,
- shared_secret: String,
cache_dir: PathBuf,
) -> talpid_ipc::Result<Self>
where
T: From<ManagementCommand> + 'static + Send,
{
- let rpc = ManagementInterface::new(tunnel_tx, shared_secret, cache_dir);
+ let rpc = ManagementInterface::new(tunnel_tx, cache_dir);
let subscriptions = rpc.subscriptions.clone();
let mut io = PubSubHandler::default();
io.extend_with(rpc.to_delegate());
let meta_io: MetaIoHandler<Meta> = io.into();
- let server = talpid_ipc::IpcServer::start_with_metadata(meta_io, meta_extractor)?;
+ let path = mullvad_paths::get_rpc_socket_path();
+ let server = talpid_ipc::IpcServer::start_with_metadata(
+ meta_io,
+ meta_extractor,
+ path.to_string_lossy().to_string(),
+ )?;
Ok(ManagementInterfaceServer {
server,
subscriptions,
})
}
- pub fn address(&self) -> &str {
- self.server.address()
+ pub fn socket_path(&self) -> &str {
+ self.server.path()
}
pub fn event_broadcaster(&self) -> EventBroadcaster {
@@ -256,12 +256,11 @@ impl ManagementInterfaceServer {
/// Consumes the server and waits for it to finish. Returns an error if the server exited
/// due to an error.
- pub fn wait(self) -> talpid_ipc::Result<()> {
+ pub fn wait(self) {
self.server.wait()
}
}
-
/// A handle that allows broadcasting messages to all subscribers of the management interface.
pub struct EventBroadcaster {
subscriptions: Arc<ActiveSubscriptions>,
@@ -300,20 +299,14 @@ impl EventBroadcaster {
struct ManagementInterface<T: From<ManagementCommand> + 'static + Send> {
subscriptions: Arc<ActiveSubscriptions>,
tx: Mutex<IntoSender<ManagementCommand, T>>,
- shared_secret: String,
cache_dir: PathBuf,
}
impl<T: From<ManagementCommand> + 'static + Send> ManagementInterface<T> {
- pub fn new(
- tx: IntoSender<ManagementCommand, T>,
- shared_secret: String,
- cache_dir: PathBuf,
- ) -> Self {
+ pub fn new(tx: IntoSender<ManagementCommand, T>, cache_dir: PathBuf) -> Self {
ManagementInterface {
subscriptions: Default::default(),
tx: Mutex::new(tx),
- shared_secret,
cache_dir,
}
}
@@ -379,16 +372,6 @@ impl<T: From<ManagementCommand> + 'static + Send> ManagementInterface<T> {
}
}
- fn check_auth(&self, meta: &Meta) -> Result<(), Error> {
- if meta.authenticated.load(Ordering::SeqCst) {
- trace!("auth success");
- Ok(())
- } else {
- trace!("auth failed");
- Err(Error::invalid_request())
- }
- }
-
fn load_history(&self) -> Result<AccountHistory, AccountHistoryError> {
let mut account_history = AccountHistory::new(&self.cache_dir);
account_history.load()?;
@@ -396,41 +379,17 @@ impl<T: From<ManagementCommand> + 'static + Send> ManagementInterface<T> {
}
}
-/// Evaluates a Result and early returns an error.
-/// If it is `Ok(val)`, evaluates to `val`.
-/// If it is `Err(e)` it early returns `Box<Future>` where the future will result in `e`.
-macro_rules! try_future {
- ($result:expr) => {
- match $result {
- ::std::result::Result::Ok(val) => val,
- ::std::result::Result::Err(e) => return Box::new(future::err(e)),
- }
- };
-}
-
impl<T: From<ManagementCommand> + 'static + Send> ManagementInterfaceApi
for ManagementInterface<T>
{
type Metadata = Meta;
- fn auth(&self, meta: Self::Metadata, shared_secret: String) -> BoxFuture<(), Error> {
- let authenticated = shared_secret == self.shared_secret;
- meta.authenticated.store(authenticated, Ordering::SeqCst);
- debug!("authenticated: {}", authenticated);
- if authenticated {
- Box::new(future::ok(()))
- } else {
- Box::new(future::err(Error::internal_error()))
- }
- }
-
fn get_account_data(
&self,
- meta: Self::Metadata,
+ _: Self::Metadata,
account_token: AccountToken,
) -> BoxFuture<AccountData, Error> {
trace!("get_account_data");
- try_future!(self.check_auth(&meta));
let (tx, rx) = sync::oneshot::channel();
let future = self
.send_command_to_daemon(ManagementCommand::GetAccountData(tx, account_token))
@@ -447,9 +406,8 @@ impl<T: From<ManagementCommand> + 'static + Send> ManagementInterfaceApi
Box::new(future)
}
- fn get_relay_locations(&self, meta: Self::Metadata) -> BoxFuture<RelayList, Error> {
+ fn get_relay_locations(&self, _: Self::Metadata) -> BoxFuture<RelayList, Error> {
trace!("get_relay_locations");
- try_future!(self.check_auth(&meta));
let (tx, rx) = sync::oneshot::channel();
let future = self
.send_command_to_daemon(ManagementCommand::GetRelayLocations(tx))
@@ -459,11 +417,10 @@ impl<T: From<ManagementCommand> + 'static + Send> ManagementInterfaceApi
fn set_account(
&self,
- meta: Self::Metadata,
+ _: Self::Metadata,
account_token: Option<AccountToken>,
) -> BoxFuture<(), Error> {
trace!("set_account");
- try_future!(self.check_auth(&meta));
let (tx, rx) = sync::oneshot::channel();
let future = self
.send_command_to_daemon(ManagementCommand::SetAccount(tx, account_token.clone()))
@@ -483,9 +440,8 @@ impl<T: From<ManagementCommand> + 'static + Send> ManagementInterfaceApi
Box::new(future)
}
- fn get_account(&self, meta: Self::Metadata) -> BoxFuture<Option<AccountToken>, Error> {
+ fn get_account(&self, _: Self::Metadata) -> BoxFuture<Option<AccountToken>, Error> {
trace!("get_account");
- try_future!(self.check_auth(&meta));
let (tx, rx) = sync::oneshot::channel();
let future = self
.send_command_to_daemon(ManagementCommand::GetAccount(tx))
@@ -495,11 +451,10 @@ impl<T: From<ManagementCommand> + 'static + Send> ManagementInterfaceApi
fn update_relay_settings(
&self,
- meta: Self::Metadata,
+ _: Self::Metadata,
constraints_update: RelaySettingsUpdate,
) -> BoxFuture<(), Error> {
trace!("update_relay_settings");
- try_future!(self.check_auth(&meta));
let (tx, rx) = sync::oneshot::channel();
let message = ManagementCommand::UpdateRelaySettings(tx, constraints_update);
@@ -509,9 +464,8 @@ impl<T: From<ManagementCommand> + 'static + Send> ManagementInterfaceApi
Box::new(future)
}
- fn get_relay_settings(&self, meta: Self::Metadata) -> BoxFuture<RelaySettings, Error> {
+ fn get_relay_settings(&self, _: Self::Metadata) -> BoxFuture<RelaySettings, Error> {
trace!("get_relay_settings");
- try_future!(self.check_auth(&meta));
let (tx, rx) = sync::oneshot::channel();
let future = self
.send_command_to_daemon(ManagementCommand::GetRelaySettings(tx))
@@ -519,9 +473,8 @@ impl<T: From<ManagementCommand> + 'static + Send> ManagementInterfaceApi
Box::new(future)
}
- fn set_allow_lan(&self, meta: Self::Metadata, allow_lan: bool) -> BoxFuture<(), Error> {
+ fn set_allow_lan(&self, _: Self::Metadata, allow_lan: bool) -> BoxFuture<(), Error> {
trace!("set_allow_lan");
- try_future!(self.check_auth(&meta));
let (tx, rx) = sync::oneshot::channel();
let future = self
.send_command_to_daemon(ManagementCommand::SetAllowLan(tx, allow_lan))
@@ -529,9 +482,8 @@ impl<T: From<ManagementCommand> + 'static + Send> ManagementInterfaceApi
Box::new(future)
}
- fn get_allow_lan(&self, meta: Self::Metadata) -> BoxFuture<bool, Error> {
+ fn get_allow_lan(&self, _: Self::Metadata) -> BoxFuture<bool, Error> {
trace!("get_allow_lan");
- try_future!(self.check_auth(&meta));
let (tx, rx) = sync::oneshot::channel();
let future = self
.send_command_to_daemon(ManagementCommand::GetAllowLan(tx))
@@ -539,9 +491,8 @@ impl<T: From<ManagementCommand> + 'static + Send> ManagementInterfaceApi
Box::new(future)
}
- fn set_auto_connect(&self, meta: Self::Metadata, auto_connect: bool) -> BoxFuture<(), Error> {
+ fn set_auto_connect(&self, _: Self::Metadata, auto_connect: bool) -> BoxFuture<(), Error> {
trace!("set_auto_connect");
- try_future!(self.check_auth(&meta));
let (tx, rx) = sync::oneshot::channel();
let future = self
.send_command_to_daemon(ManagementCommand::SetAutoConnect(tx, auto_connect))
@@ -549,9 +500,8 @@ impl<T: From<ManagementCommand> + 'static + Send> ManagementInterfaceApi
Box::new(future)
}
- fn get_auto_connect(&self, meta: Self::Metadata) -> BoxFuture<bool, Error> {
+ fn get_auto_connect(&self, _: Self::Metadata) -> BoxFuture<bool, Error> {
trace!("get_auto_connect");
- try_future!(self.check_auth(&meta));
let (tx, rx) = sync::oneshot::channel();
let future = self
.send_command_to_daemon(ManagementCommand::GetAutoConnect(tx))
@@ -559,21 +509,18 @@ impl<T: From<ManagementCommand> + 'static + Send> ManagementInterfaceApi
Box::new(future)
}
- fn connect(&self, meta: Self::Metadata) -> BoxFuture<(), Error> {
+ fn connect(&self, _: Self::Metadata) -> BoxFuture<(), Error> {
trace!("connect");
- try_future!(self.check_auth(&meta));
self.send_command_to_daemon(ManagementCommand::SetTargetState(TargetState::Secured))
}
- fn disconnect(&self, meta: Self::Metadata) -> BoxFuture<(), Error> {
+ fn disconnect(&self, _: Self::Metadata) -> BoxFuture<(), Error> {
trace!("disconnect");
- try_future!(self.check_auth(&meta));
self.send_command_to_daemon(ManagementCommand::SetTargetState(TargetState::Unsecured))
}
- fn get_state(&self, meta: Self::Metadata) -> BoxFuture<DaemonState, Error> {
+ fn get_state(&self, _: Self::Metadata) -> BoxFuture<DaemonState, Error> {
trace!("get_state");
- try_future!(self.check_auth(&meta));
let (state_tx, state_rx) = sync::oneshot::channel();
let future = self
.send_command_to_daemon(ManagementCommand::GetState(state_tx))
@@ -581,9 +528,8 @@ impl<T: From<ManagementCommand> + 'static + Send> ManagementInterfaceApi
Box::new(future)
}
- fn get_current_location(&self, meta: Self::Metadata) -> BoxFuture<GeoIpLocation, Error> {
+ fn get_current_location(&self, _: Self::Metadata) -> BoxFuture<GeoIpLocation, Error> {
trace!("get_current_location");
- try_future!(self.check_auth(&meta));
let (tx, rx) = sync::oneshot::channel();
let future = self
.send_command_to_daemon(ManagementCommand::GetCurrentLocation(tx))
@@ -591,15 +537,13 @@ impl<T: From<ManagementCommand> + 'static + Send> ManagementInterfaceApi
Box::new(future)
}
- fn shutdown(&self, meta: Self::Metadata) -> BoxFuture<(), Error> {
+ fn shutdown(&self, _: Self::Metadata) -> BoxFuture<(), Error> {
trace!("shutdown");
- try_future!(self.check_auth(&meta));
self.send_command_to_daemon(ManagementCommand::Shutdown)
}
- fn get_account_history(&self, meta: Self::Metadata) -> BoxFuture<Vec<AccountToken>, Error> {
+ fn get_account_history(&self, _: Self::Metadata) -> BoxFuture<Vec<AccountToken>, Error> {
trace!("get_account_history");
- try_future!(self.check_auth(&meta));
Box::new(future::result(
self.load_history()
.map(|history| history.get_accounts().to_vec())
@@ -612,11 +556,10 @@ impl<T: From<ManagementCommand> + 'static + Send> ManagementInterfaceApi
fn remove_account_from_history(
&self,
- meta: Self::Metadata,
+ _: Self::Metadata,
account_token: AccountToken,
) -> BoxFuture<(), Error> {
trace!("remove_account_from_history");
- try_future!(self.check_auth(&meta));
Box::new(future::result(
self.load_history()
.and_then(|mut history| history.remove_account_token(account_token))
@@ -630,13 +573,8 @@ impl<T: From<ManagementCommand> + 'static + Send> ManagementInterfaceApi
))
}
- fn set_openvpn_mssfix(
- &self,
- meta: Self::Metadata,
- mssfix: Option<u16>,
- ) -> BoxFuture<(), Error> {
+ fn set_openvpn_mssfix(&self, _: Self::Metadata, mssfix: Option<u16>) -> BoxFuture<(), Error> {
trace!("set_openvpn_mssfix");
- try_future!(self.check_auth(&meta));
let (tx, rx) = sync::oneshot::channel();
let future = self
.send_command_to_daemon(ManagementCommand::SetOpenVpnMssfix(tx, mssfix))
@@ -647,11 +585,10 @@ impl<T: From<ManagementCommand> + 'static + Send> ManagementInterfaceApi
fn set_openvpn_enable_ipv6(
&self,
- meta: Self::Metadata,
+ _: Self::Metadata,
enable_ipv6: bool,
) -> BoxFuture<(), Error> {
trace!("set_openvpn_enable_ipv6");
- try_future!(self.check_auth(&meta));
let (tx, rx) = sync::oneshot::channel();
let future = self
.send_command_to_daemon(ManagementCommand::SetOpenVpnEnableIpv6(tx, enable_ipv6))
@@ -660,9 +597,8 @@ impl<T: From<ManagementCommand> + 'static + Send> ManagementInterfaceApi
Box::new(future)
}
- fn get_tunnel_options(&self, meta: Self::Metadata) -> BoxFuture<TunnelOptions, Error> {
+ fn get_tunnel_options(&self, _: Self::Metadata) -> BoxFuture<TunnelOptions, Error> {
trace!("get_tunnel_options");
- try_future!(self.check_auth(&meta));
let (tx, rx) = sync::oneshot::channel();
let future = self
.send_command_to_daemon(ManagementCommand::GetTunnelOptions(tx))
@@ -670,8 +606,7 @@ impl<T: From<ManagementCommand> + 'static + Send> ManagementInterfaceApi
Box::new(future)
}
- fn get_current_version(&self, meta: Self::Metadata) -> BoxFuture<String, Error> {
- try_future!(self.check_auth(&meta));
+ fn get_current_version(&self, _: Self::Metadata) -> BoxFuture<String, Error> {
let (tx, rx) = sync::oneshot::channel();
let future = self
.send_command_to_daemon(ManagementCommand::GetCurrentVersion(tx))
@@ -680,8 +615,7 @@ impl<T: From<ManagementCommand> + 'static + Send> ManagementInterfaceApi
Box::new(future)
}
- fn get_version_info(&self, meta: Self::Metadata) -> BoxFuture<version::AppVersionInfo, Error> {
- try_future!(self.check_auth(&meta));
+ fn get_version_info(&self, _: Self::Metadata) -> BoxFuture<version::AppVersionInfo, Error> {
let (tx, rx) = sync::oneshot::channel();
let future = self
.send_command_to_daemon(ManagementCommand::GetVersionInfo(tx))
@@ -699,15 +633,8 @@ impl<T: From<ManagementCommand> + 'static + Send> ManagementInterfaceApi
Box::new(future)
}
- fn new_state_subscribe(
- &self,
- meta: Self::Metadata,
- subscriber: pubsub::Subscriber<DaemonState>,
- ) {
+ fn new_state_subscribe(&self, _: Self::Metadata, subscriber: pubsub::Subscriber<DaemonState>) {
trace!("new_state_subscribe");
- if self.check_auth(&meta).is_err() {
- return;
- }
Self::subscribe(subscriber, &self.subscriptions.new_state_subscriptions);
}
@@ -716,11 +643,8 @@ impl<T: From<ManagementCommand> + 'static + Send> ManagementInterfaceApi
Self::unsubscribe(id, &self.subscriptions.new_state_subscriptions)
}
- fn error_subscribe(&self, meta: Self::Metadata, subscriber: pubsub::Subscriber<Vec<String>>) {
+ fn error_subscribe(&self, _: Self::Metadata, subscriber: pubsub::Subscriber<Vec<String>>) {
trace!("error_subscribe");
- if self.check_auth(&meta).is_err() {
- return;
- }
Self::subscribe(subscriber, &self.subscriptions.error_subscriptions);
}
@@ -737,7 +661,6 @@ impl<T: From<ManagementCommand> + 'static + Send> ManagementInterfaceApi
#[derive(Clone, Debug, Default)]
pub struct Meta {
session: Option<Arc<Session>>,
- authenticated: Arc<AtomicBool>,
}
/// Make the `Meta` type possible to use as jsonrpc metadata type.
@@ -751,9 +674,8 @@ impl PubSubMetadata for Meta {
}
/// Metadata extractor function for `Meta`.
-fn meta_extractor(context: &jsonrpc_ws_server::RequestContext) -> Meta {
+fn meta_extractor(context: &jsonrpc_ipc_server::RequestContext) -> Meta {
Meta {
- session: Some(Arc::new(Session::new(context.sender()))),
- authenticated: Arc::new(AtomicBool::new(false)),
+ session: Some(Arc::new(Session::new(context.sender.clone()))),
}
}
diff --git a/mullvad-daemon/src/rpc_address_file.rs b/mullvad-daemon/src/rpc_address_file.rs
deleted file mode 100644
index d0df2c1919..0000000000
--- a/mullvad-daemon/src/rpc_address_file.rs
+++ /dev/null
@@ -1,88 +0,0 @@
-use std::fs::{self, File, OpenOptions};
-use std::io::{self, Write};
-use std::path::{Path, PathBuf};
-
-use mullvad_paths;
-
-#[cfg(windows)]
-extern crate winapi;
-
-error_chain! {
- errors {
- UnknownFilePath {
- description("Failed to find path for RPC connection info file")
- }
- CreateDirFailed(path: PathBuf) {
- description("Failed to create directory for RPC connection info file")
- display(
- "Failed to create directory for RPC connection info file: {}",
- path.display(),
- )
- }
- WriteFailed(path: PathBuf) {
- description("Failed to write RPC connection info to file")
- display("Failed to write RPC connection info to {}", path.display())
- }
- RemoveFailed(path: PathBuf) {
- description("Failed to remove file")
- display("Failed to remove {}", path.display())
- }
- }
-}
-
-/// Writes down the RPC connection info to the RPC file.
-pub fn write(rpc_address: &str, shared_secret: &str) -> Result<()> {
- // Avoids opening an existing file owned by another user and writing sensitive data to it.
- remove()?;
-
- let file_path =
- mullvad_paths::get_rpc_address_path().chain_err(|| ErrorKind::UnknownFilePath)?;
-
- if let Some(parent_dir) = file_path.parent() {
- fs::create_dir_all(parent_dir)
- .chain_err(|| ErrorKind::CreateDirFailed(parent_dir.to_owned()))?;
- }
-
- open_file(&file_path)
- .and_then(|mut file| write!(file, "{}\n{}\n", rpc_address, shared_secret))
- .chain_err(|| ErrorKind::WriteFailed(file_path.clone()))?;
-
- debug!("Wrote RPC connection info to {}", file_path.display());
- Ok(())
-}
-
-/// Removes the RPC file, if it exists.
-pub fn remove() -> Result<()> {
- let file_path =
- mullvad_paths::get_rpc_address_path().chain_err(|| ErrorKind::UnknownFilePath)?;
-
- if let Err(error) = fs::remove_file(&file_path) {
- if error.kind() == io::ErrorKind::NotFound {
- // No previously existing file
- Ok(())
- } else {
- Err(error).chain_err(|| ErrorKind::RemoveFailed(file_path))
- }
- } else {
- Ok(())
- }
-}
-
-fn open_file(path: &Path) -> io::Result<File> {
- let mut open_options = OpenOptions::new();
- open_options.write(true).truncate(true).create(true);
-
- #[cfg(windows)]
- {
- use std::os::windows::fs::OpenOptionsExt;
- open_options.share_mode(winapi::um::winnt::FILE_SHARE_READ);
- }
-
- let file = open_options.open(path)?;
- #[cfg(unix)]
- {
- use std::os::unix::fs::PermissionsExt;
- file.set_permissions(PermissionsExt::from_mode(0o644))?;
- }
- Ok(file)
-}
diff --git a/mullvad-daemon/src/rpc_uniqueness_check.rs b/mullvad-daemon/src/rpc_uniqueness_check.rs
index 76130f72e8..37bf8a3f60 100644
--- a/mullvad-daemon/src/rpc_uniqueness_check.rs
+++ b/mullvad-daemon/src/rpc_uniqueness_check.rs
@@ -1,7 +1,8 @@
use error_chain::ChainedError;
use log::Level;
-use mullvad_ipc_client::DaemonRpcClient;
+use mullvad_ipc_client::new_standalone_ipc_client;
+use mullvad_paths;
/// Checks if there is another instance of the daemon running.
@@ -9,7 +10,7 @@ use mullvad_ipc_client::DaemonRpcClient;
/// Tries to connect to another daemon and perform a simple RPC call. If it fails, assumes the
/// other daemon has stopped.
pub fn is_another_instance_running() -> bool {
- match DaemonRpcClient::new() {
+ match new_standalone_ipc_client(&mullvad_paths::get_rpc_socket_path()) {
Ok(_) => true,
Err(error) => {
let msg =
diff --git a/mullvad-ipc-client/Cargo.toml b/mullvad-ipc-client/Cargo.toml
index 7a7513eeab..443cffa885 100644
--- a/mullvad-ipc-client/Cargo.toml
+++ b/mullvad-ipc-client/Cargo.toml
@@ -12,6 +12,13 @@ serde = "1.0"
talpid-ipc = { path = "../talpid-ipc" }
talpid-types = { path = "../talpid-types" }
mullvad-paths = { path = "../mullvad-paths" }
+jsonrpc-client-core = { git = "https://github.com/mullvad/jsonrpc-client-rs", branch = "master" }
+jsonrpc-client-ipc = { git = "https://github.com/mullvad/jsonrpc-client-rs", branch = "master" }
+tokio-core = "0.1"
+tokio-timer = "0.1"
+futures = "0.1"
+log = "0.4"
+
[target.'cfg(windows)'.dependencies]
winapi = { version = "0.3.5", features = ["accctrl", "aclapi", "securitybaseapi", "winbase", "winerror", "winnt"] }
diff --git a/mullvad-ipc-client/src/lib.rs b/mullvad-ipc-client/src/lib.rs
index 6c1734a4c9..62a829b4d0 100644
--- a/mullvad-ipc-client/src/lib.rs
+++ b/mullvad-ipc-client/src/lib.rs
@@ -1,15 +1,25 @@
#[macro_use]
+extern crate log;
+
+#[macro_use]
extern crate error_chain;
+
+extern crate jsonrpc_client_core;
+extern crate jsonrpc_client_ipc;
+
+extern crate futures;
extern crate mullvad_paths;
extern crate mullvad_types;
extern crate serde;
extern crate talpid_ipc;
extern crate talpid_types;
+extern crate tokio_core;
+extern crate tokio_timer;
-use std::fs::File;
-use std::io::{BufRead, BufReader};
-use std::path::{Path, PathBuf};
+use std::path::Path;
use std::sync::mpsc;
+use std::thread;
+use std::time::Duration;
use mullvad_types::account::{AccountData, AccountToken};
use mullvad_types::location::GeoIpLocation;
@@ -18,10 +28,14 @@ use mullvad_types::relay_list::RelayList;
use mullvad_types::states::DaemonState;
use mullvad_types::version::AppVersionInfo;
use serde::{Deserialize, Serialize};
-use talpid_ipc::WsIpcClient;
use talpid_types::net::TunnelOptions;
-use platform_specific::ensure_written_by_admin;
+use futures::stream::{self, Stream};
+use futures::sync::oneshot;
+use jsonrpc_client_core::{Client, ClientHandle, Future};
+pub use jsonrpc_client_core::{Error as RpcError, ErrorKind as RpcErrorKind};
+use jsonrpc_client_ipc::IpcTransport;
+use tokio_core::reactor;
error_chain! {
errors {
@@ -29,32 +43,6 @@ error_chain! {
description("Failed to authenticate the connection with the daemon")
}
- EmptyRpcFile(path: PathBuf) {
- description("RPC connection file is empty")
- display("RPC connection file \"{}\" is empty", path.display())
- }
-
- InsecureRpcFile(path: PathBuf) {
- description(
- "RPC connection file is insecure because it might not have been written by an \
- administrator user"
- )
- display(
- "RPC connection file \"{}\" is insecure because it might not have been written by \
- an administrator user", path.display()
- )
- }
-
- MissingRpcCredentials(path: PathBuf) {
- description("no credentials found in RPC connection file")
- display("no credentials found in RPC connection file {}", path.display())
- }
-
- ReadRpcFileError(path: PathBuf) {
- description("Failed to read RPC connection information")
- display("Failed to read RPC connection information from {}", path.display())
- }
-
RpcCallError(method: String) {
description("Failed to call RPC method")
display("Failed to call RPC method \"{}\"", method)
@@ -69,6 +57,14 @@ error_chain! {
description("Failed to start RPC client")
display("Failed to start RPC client to {}", address)
}
+
+ TokioError {
+ description("Failed to setup a standalone event loop")
+ }
+
+ TransportError {
+ description("Failed to setup a transport")
+ }
}
links {
UnknownRpcAddressPath(mullvad_paths::Error, mullvad_paths::ErrorKind);
@@ -77,66 +73,60 @@ error_chain! {
static NO_ARGS: [u8; 0] = [];
-pub struct DaemonRpcClient {
- rpc_client: WsIpcClient,
-}
-
-impl DaemonRpcClient {
- pub fn new() -> Result<Self> {
- Self::with_rpc_address_file(mullvad_paths::get_rpc_address_path()?)
- }
-
- pub fn with_rpc_address_file<P: AsRef<Path>>(file_path: P) -> Result<Self> {
- ensure_written_by_admin(&file_path)?;
-
- let (address, credentials) = Self::read_rpc_file(file_path)?;
-
- Self::with_address_and_credentials(address, credentials)
- }
-
- pub fn with_insecure_rpc_address_file<P: AsRef<Path>>(file_path: P) -> Result<Self> {
- let (address, credentials) = Self::read_rpc_file(file_path)?;
-
- Self::with_address_and_credentials(address, credentials)
- }
-
- fn with_address_and_credentials(address: String, credentials: String) -> Result<Self> {
- let rpc_client =
- WsIpcClient::connect(&address).chain_err(|| ErrorKind::StartRpcClient(address))?;
- let mut instance = DaemonRpcClient { rpc_client };
+pub fn new_standalone_transport<
+ F: Send + 'static + FnOnce(String, reactor::Handle) -> Result<T>,
+ T: jsonrpc_client_core::Transport,
+>(
+ rpc_path: String,
+ transport_func: F,
+) -> Result<DaemonRpcClient> {
+ let (tx, rx) = oneshot::channel();
+ thread::spawn(move || match spawn_transport(rpc_path, transport_func) {
+ Err(e) => tx
+ .send(Err(e))
+ .expect("Failed to send error back to caller"),
+ Ok((mut core, client, client_handle)) => {
+ tx.send(Ok(client_handle))
+ .expect("Failed to send client handle");
+ if let Err(e) = core.run(client) {
+ error!("JSON-RPC client failed: {}", e.description());
+ }
+ }
+ });
- instance
- .auth(&credentials)
- .chain_err(|| ErrorKind::AuthenticationError)?;
+ rx.wait()
+ .chain_err(|| ErrorKind::TransportError)?
+ .map(|client_handle| DaemonRpcClient::new(client_handle))
+}
- Ok(instance)
- }
+pub fn new_standalone_ipc_client(path: &impl AsRef<Path>) -> Result<DaemonRpcClient> {
+ let path = path.as_ref().to_string_lossy().to_string();
- fn read_rpc_file<P>(file_path: P) -> Result<(String, String)>
- where
- P: AsRef<Path>,
- {
- let file_path = file_path.as_ref();
- let rpc_file = File::open(file_path)
- .chain_err(|| ErrorKind::ReadRpcFileError(file_path.to_owned()))?;
+ new_standalone_transport(path, |path, handle| {
+ IpcTransport::new(&path, &handle).chain_err(|| ErrorKind::TransportError)
+ })
+}
- let reader = BufReader::new(rpc_file);
- let mut lines = reader.lines();
+fn spawn_transport<
+ F: Send + FnOnce(String, reactor::Handle) -> Result<T>,
+ T: jsonrpc_client_core::Transport,
+>(
+ address: String,
+ transport_func: F,
+) -> Result<(reactor::Core, Client<T>, ClientHandle)> {
+ let core = reactor::Core::new().chain_err(|| ErrorKind::TokioError)?;
+ let (client, client_handle) = transport_func(address, core.handle())?.into_client();
+ Ok((core, client, client_handle))
+}
- let address = lines
- .next()
- .ok_or_else(|| ErrorKind::EmptyRpcFile(file_path.to_owned()))?
- .chain_err(|| ErrorKind::ReadRpcFileError(file_path.to_owned()))?;
- let credentials = lines
- .next()
- .ok_or_else(|| ErrorKind::MissingRpcCredentials(file_path.to_owned()))?
- .chain_err(|| ErrorKind::ReadRpcFileError(file_path.to_owned()))?;
+pub struct DaemonRpcClient {
+ rpc_client: jsonrpc_client_core::ClientHandle,
+}
- Ok((address, credentials))
- }
- pub fn auth(&mut self, credentials: &str) -> Result<()> {
- self.call("auth", &[credentials])
+impl DaemonRpcClient {
+ pub fn new(rpc_client: ClientHandle) -> Self {
+ DaemonRpcClient { rpc_client }
}
pub fn connect(&mut self) -> Result<()> {
@@ -219,139 +209,43 @@ impl DaemonRpcClient {
self.call("update_relay_settings", &[update])
}
- pub fn call<A, O>(&mut self, method: &str, args: &A) -> Result<O>
+ pub fn call<A, O>(&mut self, method: &'static str, args: &A) -> Result<O>
where
- A: Serialize,
- O: for<'de> Deserialize<'de>,
+ A: Serialize + Send + 'static,
+ O: for<'de> Deserialize<'de> + Send + 'static,
{
self.rpc_client
- .call(method, args)
+ .call_method(method, args)
+ .wait()
.chain_err(|| ErrorKind::RpcCallError(method.to_owned()))
}
pub fn new_state_subscribe(&mut self) -> Result<mpsc::Receiver<DaemonState>> {
- self.subscribe("new_state")
- }
-
- pub fn subscribe<T>(&mut self, event: &str) -> Result<mpsc::Receiver<T>>
- where
- T: for<'de> serde::Deserialize<'de> + Send + 'static,
- {
- let (event_tx, event_rx) = mpsc::channel();
- let subscribe_method = format!("{}_subscribe", event);
- let unsubscribe_method = format!("{}_unsubscribe", event);
-
- self.rpc_client
- .subscribe::<T, T>(subscribe_method, unsubscribe_method, event_tx)
- .chain_err(|| ErrorKind::RpcSubscribeError(event.to_owned()))?;
-
- Ok(event_rx)
- }
-}
-
-#[cfg(unix)]
-mod platform_specific {
- use std::os::unix::fs::MetadataExt;
-
- use super::*;
-
- pub fn ensure_written_by_admin<P: AsRef<Path>>(path: P) -> Result<()> {
- let path = path.as_ref();
- let metadata = path
- .metadata()
- .chain_err(|| ErrorKind::ReadRpcFileError(path.to_owned()))?;
-
- let is_owned_by_root = metadata.uid() == 0;
- let is_read_only_by_non_owner = (metadata.mode() & 0o022) == 0;
-
- ensure!(
- is_owned_by_root && is_read_only_by_non_owner,
- ErrorKind::InsecureRpcFile(path.to_owned())
- );
-
- Ok(())
- }
-}
-
-#[cfg(windows)]
-mod platform_specific {
- extern crate winapi;
+ let client = self.rpc_client.clone();
+ let mut current_state = self.get_state()?;
+ let first_message = stream::once(Ok(current_state.clone()));
- use std::iter::once;
- use std::os::windows::ffi::OsStrExt;
- use std::ptr;
+ let (tx, rx) = mpsc::channel();
- use self::winapi::shared::winerror::ERROR_SUCCESS;
- use self::winapi::um::accctrl::SE_FILE_OBJECT;
- use self::winapi::um::aclapi::GetNamedSecurityInfoW;
- use self::winapi::um::securitybaseapi::IsWellKnownSid;
- use self::winapi::um::winbase::LocalFree;
- use self::winapi::um::winnt::{
- WinBuiltinAdministratorsSid, OWNER_SECURITY_INFORMATION, PSECURITY_DESCRIPTOR, PSID,
- };
+ let polled = tokio_timer::wheel()
+ .build()
+ .interval(Duration::from_secs(1))
+ .then(move |_| client.call_method("get_state", &NO_ARGS));
- use super::*;
-
- mod errors {
- error_chain! {
- errors {
- GetSecurityInfoError {
- description("Failed to get security information of RPC address file")
- }
-
- OwnerNotAdmin {
- description("Owner of RPC address file is not an administrator")
- }
- }
- }
- }
- use self::errors::{ErrorKind as WinErrorKind, Result as WinResult};
-
- pub fn ensure_written_by_admin<P: AsRef<Path>>(file_path: P) -> Result<()> {
- let path = file_path.as_ref();
-
- ensure_owned_by_admin(&path).chain_err(|| ErrorKind::InsecureRpcFile(path.to_owned()))?;
-
- Ok(())
- }
-
- fn ensure_owned_by_admin<P: AsRef<Path>>(path: P) -> WinResult<()> {
- let file_path: Vec<u16> = path
- .as_ref()
- .as_os_str()
- .encode_wide()
- .chain(once(0))
- .collect();
-
- unsafe {
- let mut owner_sid: PSID = ptr::null_mut();
- let mut security_descriptor: PSECURITY_DESCRIPTOR = ptr::null_mut();
-
- let get_security_info_result = GetNamedSecurityInfoW(
- file_path.as_ptr(),
- SE_FILE_OBJECT,
- OWNER_SECURITY_INFORMATION,
- &mut owner_sid,
- ptr::null_mut(),
- ptr::null_mut(),
- ptr::null_mut(),
- &mut security_descriptor,
- );
-
- ensure!(
- get_security_info_result == ERROR_SUCCESS,
- WinErrorKind::GetSecurityInfoError
- );
-
- let sid_check_result = IsWellKnownSid(owner_sid, WinBuiltinAdministratorsSid);
-
- if !LocalFree(security_descriptor as *mut _).is_null() {
- panic!("Failed to deallocate security descriptor");
- }
-
- ensure!(sid_check_result != 0, WinErrorKind::OwnerNotAdmin);
-
- Ok(())
- }
+ thread::spawn(move || {
+ let _ = first_message
+ .chain(polled)
+ .for_each(move |state| {
+ if state != current_state {
+ current_state = state;
+ if tx.send(state).is_err() {
+ trace!("can't send new state to subscriber");
+ return Err(jsonrpc_client_core::ErrorKind::Shutdown.into());
+ };
+ }
+ Ok(())
+ }).wait();
+ });
+ Ok(rx)
}
}
diff --git a/mullvad-paths/src/lib.rs b/mullvad-paths/src/lib.rs
index a2f5478d31..d05923c03a 100644
--- a/mullvad-paths/src/lib.rs
+++ b/mullvad-paths/src/lib.rs
@@ -52,7 +52,7 @@ pub mod resources;
pub use resources::get_resource_dir;
mod rpc_address;
-pub use rpc_address::get_rpc_address_path;
+pub use rpc_address::get_rpc_socket_path;
mod settings;
pub use settings::settings_dir;
diff --git a/mullvad-paths/src/rpc_address.rs b/mullvad-paths/src/rpc_address.rs
index a97b3e0c36..f71e7a4edd 100644
--- a/mullvad-paths/src/rpc_address.rs
+++ b/mullvad-paths/src/rpc_address.rs
@@ -1,24 +1,12 @@
-use Result;
-
use std::env;
use std::path::PathBuf;
-const RPC_ADDRESS_FILENAME: &str = ".mullvad_rpc_address";
-
-pub fn get_rpc_address_path() -> Result<PathBuf> {
- match env::var_os("MULLVAD_RPC_ADDRESS_PATH") {
- Some(path) => Ok(PathBuf::from(path)),
- None => get_default_rpc_address_dir().map(|dir| dir.join(RPC_ADDRESS_FILENAME)),
- }
-}
-
-fn get_default_rpc_address_dir() -> Result<PathBuf> {
- #[cfg(unix)]
- {
- Ok(PathBuf::from("/tmp"))
- }
- #[cfg(windows)]
- {
- ::get_allusersprofile_dir().map(|dir| dir.join(::PRODUCT_NAME))
+pub fn get_rpc_socket_path() -> PathBuf {
+ match env::var_os("MULLVAD_RPC_SOCKET_PATH") {
+ Some(path) => PathBuf::from(path),
+ #[cfg(unix)]
+ None => PathBuf::from("/var/run/mullvad-vpn"),
+ #[cfg(windows)]
+ None => PathBuf::from("//./pipe/Mullvad VPN"),
}
}
diff --git a/mullvad-tests/Cargo.toml b/mullvad-tests/Cargo.toml
index 7e7169c3f4..18f8b959d8 100644
--- a/mullvad-tests/Cargo.toml
+++ b/mullvad-tests/Cargo.toml
@@ -17,6 +17,10 @@ notify = "4.0"
openvpn-plugin = { version = "0.3", features = ["serde"] }
talpid-ipc = { path = "../talpid-ipc" }
tempfile = "3.0"
+jsonrpc-client-core = { git = "https://github.com/mullvad/jsonrpc-client-rs", branch = "master" }
+jsonrpc-client-ipc = { git = "https://github.com/mullvad/jsonrpc-client-rs", branch = "master" }
+tokio-core = "0.1"
+futures = "0.1.23"
[target.'cfg(unix)'.dependencies]
libc = "0.2"
diff --git a/mullvad-tests/src/lib.rs b/mullvad-tests/src/lib.rs
index 0e2f404258..b90aaa3157 100644
--- a/mullvad-tests/src/lib.rs
+++ b/mullvad-tests/src/lib.rs
@@ -1,5 +1,7 @@
#[macro_use]
extern crate duct;
+extern crate jsonrpc_client_core;
+extern crate jsonrpc_client_ipc;
#[cfg(unix)]
extern crate libc;
extern crate mullvad_ipc_client;
@@ -9,6 +11,9 @@ extern crate openvpn_plugin;
extern crate talpid_ipc;
extern crate tempfile;
+extern crate futures;
+extern crate tokio_core;
+
pub mod mock_openvpn;
use std::collections::HashMap;
@@ -18,12 +23,15 @@ use std::sync::{mpsc, Arc};
use std::time::{Duration, Instant};
use std::{cmp, thread};
-use mullvad_ipc_client::DaemonRpcClient;
+use futures::sync::oneshot;
+use jsonrpc_client_core::{Future, Transport};
+use jsonrpc_client_ipc::IpcTransport;
+use mullvad_ipc_client::{DaemonRpcClient, ResultExt};
use mullvad_paths::resources::API_CA_FILENAME;
use notify::{RawEvent, RecommendedWatcher, RecursiveMode, Watcher};
use openvpn_plugin::types::OpenVpnPluginEvent;
-use talpid_ipc::WsIpcClient;
use tempfile::TempDir;
+use tokio_core::reactor::Core;
use self::mock_openvpn::MOCK_OPENVPN_ARGS_FILE;
use self::platform_specific::*;
@@ -261,50 +269,42 @@ fn prepare_relay_list<T: AsRef<Path>>(path: T) {
pub struct DaemonRunner {
process: Option<duct::Handle>,
mock_openvpn_args_file: PathBuf,
- rpc_address_file: PathBuf,
+ rpc_socket_path: PathBuf,
_temp_dir: TempDir,
}
impl DaemonRunner {
pub fn spawn_with_real_rpc_address_file() -> Self {
- Self::spawn_internal(false)
+ Self::spawn_internal()
}
pub fn spawn() -> Self {
- Self::spawn_internal(true)
+ Self::spawn_internal()
}
- fn spawn_internal(mock_rpc_address_file: bool) -> Self {
+ fn spawn_internal() -> Self {
let (temp_dir, cache_dir, resource_dir, settings_dir) = prepare_test_dirs();
let mock_openvpn_args_file = temp_dir.path().join(MOCK_OPENVPN_ARGS_FILE);
- let rpc_address_file = if mock_rpc_address_file {
- temp_dir.path().join(".mullvad_rpc_address")
- } else {
- mullvad_paths::get_rpc_address_path().expect("Failed to build RPC connection file path")
- };
- let mut expression = cmd!(DAEMON_EXECUTABLE_PATH, "-v", "--disable-log-to-file")
+ let rpc_socket_path = temp_dir.path().join("rpc_socket");
+
+ let expression = cmd!(DAEMON_EXECUTABLE_PATH, "-v", "--disable-log-to-file")
.dir("..")
.env("MULLVAD_CACHE_DIR", cache_dir)
+ .env("MULLVAD_RPC_SOCKET_PATH", rpc_socket_path.clone())
.env("MULLVAD_RESOURCE_DIR", resource_dir)
.env("MULLVAD_SETTINGS_DIR", settings_dir)
.env("MOCK_OPENVPN_ARGS_FILE", mock_openvpn_args_file.clone())
.stdout_null()
.stderr_null();
- if mock_rpc_address_file {
- expression = expression.env(
- "MULLVAD_RPC_ADDRESS_PATH",
- rpc_address_file.display().to_string(),
- );
- }
let process = expression.start().expect("Failed to start daemon");
DaemonRunner {
process: Some(process),
mock_openvpn_args_file,
- rpc_address_file,
+ rpc_socket_path,
_temp_dir: temp_dir,
}
}
@@ -314,10 +314,12 @@ impl DaemonRunner {
}
pub fn rpc_client(&mut self) -> Result<DaemonRpcClient> {
- wait_for_file(&self.rpc_address_file);
-
- DaemonRpcClient::with_insecure_rpc_address_file(&self.rpc_address_file)
- .map_err(|error| format!("Failed to create RPC client: {}", error))
+ wait_for_file(&self.rpc_socket_path);
+ let socket_path: String = self.rpc_socket_path.to_string_lossy().to_string();
+ mullvad_ipc_client::new_standalone_transport(socket_path, |path, handle| {
+ IpcTransport::new(&path, &handle)
+ .chain_err(|| mullvad_ipc_client::ErrorKind::TransportError)
+ }).map_err(|e| format!("Failed to construct an RPC client - {}", e))
}
#[cfg(unix)]
@@ -360,35 +362,38 @@ impl Drop for DaemonRunner {
process.kill().unwrap();
}
}
-
- let _ = fs::remove_file(&self.rpc_address_file);
}
}
pub struct MockOpenVpnPluginRpcClient {
- credentials: String,
- rpc: WsIpcClient,
+ rpc: jsonrpc_client_core::ClientHandle,
}
impl MockOpenVpnPluginRpcClient {
- pub fn new(address: String, credentials: String) -> Result<Self> {
- let rpc = WsIpcClient::connect(&address).map_err(|error| {
- format!("Failed to create Mock OpenVPN plugin RPC client: {}", error)
- })?;
+ fn spawn_event_loop(address: String) -> Result<jsonrpc_client_core::ClientHandle> {
+ let (tx, rx) = oneshot::channel();
+ thread::spawn(move || {
+ let mut core = Core::new().expect("failed to spawn an event loop");
- Ok(MockOpenVpnPluginRpcClient { rpc, credentials })
- }
+ let result = IpcTransport::new(&address, &core.handle())
+ .map_err(|error| {
+ format!("Failed to create Mock OpenVPN plugin RPC client: {}", error)
+ }).map(Transport::into_client);
+ match result {
+ Ok((client, client_handle)) => {
+ tx.send(Ok(client_handle)).unwrap();
+ core.run(client).expect("client failed");
+ }
+ Err(e) => tx.send(Err(e)).unwrap(),
+ }
+ });
- pub fn authenticate(&mut self) -> Result<bool> {
- self.rpc
- .call("authenticate", &[&self.credentials])
- .map_err(|error| format!("Failed to authenticate mock OpenVPN IPC client: {}", error))
+ rx.wait().unwrap()
}
- pub fn authenticate_with(&mut self, credentials: &str) -> Result<bool> {
- self.rpc
- .call("authenticate", &[credentials])
- .map_err(|error| format!("Failed to authenticate mock OpenVPN IPC client: {}", error))
+ pub fn new(address: String) -> Result<Self> {
+ let rpc = Self::spawn_event_loop(address)?;
+ Ok(MockOpenVpnPluginRpcClient { rpc })
}
pub fn up(&mut self) -> Result<()> {
@@ -417,7 +422,8 @@ impl MockOpenVpnPluginRpcClient {
env: HashMap<String, String>,
) -> Result<()> {
self.rpc
- .call("openvpn_event", &(event, env))
+ .call_method("openvpn_event", &(event, env))
+ .wait()
.map_err(|error| format!("Failed to send mock OpenVPN event {:?}: {}", event, error))
}
}
diff --git a/mullvad-tests/tests/connection.rs b/mullvad-tests/tests/connection.rs
index 88e8a88c74..75ee04d788 100644
--- a/mullvad-tests/tests/connection.rs
+++ b/mullvad-tests/tests/connection.rs
@@ -34,11 +34,6 @@ const CONNECTED_STATE: DaemonState = DaemonState {
target_state: TargetState::Secured,
};
-const DISCONNECTING_STATE: DaemonState = DaemonState {
- state: SecurityState::Secured,
- target_state: TargetState::Unsecured,
-};
-
#[test]
fn spawns_openvpn() {
let mut daemon = DaemonRunner::spawn();
@@ -91,86 +86,6 @@ fn changes_to_connecting_state() {
}
#[test]
-fn ignores_event_from_unauthorized_connection_from_openvpn_plugin() {
- let mut daemon = DaemonRunner::spawn();
- let mut rpc_client = daemon.rpc_client().unwrap();
- let openvpn_args_file = daemon.mock_openvpn_args_file();
- let mut openvpn_args_file_events = PathWatcher::watch(&openvpn_args_file).unwrap();
- let state_events = rpc_client.new_state_subscribe().unwrap();
-
- rpc_client.set_account(Some("123456".to_owned())).unwrap();
- rpc_client.connect().unwrap();
-
- assert_state_event(&state_events, CONNECTING_STATE);
- openvpn_args_file_events.assert_create_write_close_sequence();
-
- let mut mock_plugin_client = create_mock_openvpn_plugin_client(openvpn_args_file);
- let call_result = mock_plugin_client.up();
-
- assert!(call_result.is_err());
- assert_no_state_event(&state_events);
- assert_eq!(rpc_client.get_state().unwrap(), CONNECTING_STATE);
-}
-
-#[test]
-fn authentication_credentials() {
- let mut daemon = DaemonRunner::spawn();
- let mut rpc_client = daemon.rpc_client().unwrap();
- let openvpn_args_file = daemon.mock_openvpn_args_file();
- let mut openvpn_args_file_events = PathWatcher::watch(&openvpn_args_file).unwrap();
- let state_events = rpc_client.new_state_subscribe().unwrap();
-
- rpc_client.set_account(Some("123456".to_owned())).unwrap();
- rpc_client.connect().unwrap();
-
- assert_state_event(&state_events, CONNECTING_STATE);
- openvpn_args_file_events.assert_create_write_close_sequence();
-
- let mut mock_plugin_client = create_mock_openvpn_plugin_client(openvpn_args_file);
-
- assert_eq!(
- mock_plugin_client.authenticate_with(&String::new()),
- Ok(false)
- );
- assert_eq!(
- mock_plugin_client.authenticate_with(&"fake-secret".to_owned()),
- Ok(false)
- );
- assert_eq!(mock_plugin_client.authenticate(), Ok(true));
- // Ensure it doesn't accept additional incorrect credentials
- assert_eq!(
- mock_plugin_client.authenticate_with(&"different-secret".to_owned()),
- Ok(false)
- );
-}
-
-#[test]
-fn separate_connections_have_independent_authentication() {
- let mut daemon = DaemonRunner::spawn();
- let mut rpc_client = daemon.rpc_client().unwrap();
- let openvpn_args_file = daemon.mock_openvpn_args_file();
- let mut openvpn_args_file_events = PathWatcher::watch(&openvpn_args_file).unwrap();
- let state_events = rpc_client.new_state_subscribe().unwrap();
-
- rpc_client.set_account(Some("123456".to_owned())).unwrap();
- rpc_client.connect().unwrap();
-
- assert_state_event(&state_events, CONNECTING_STATE);
- openvpn_args_file_events.assert_create_write_close_sequence();
-
- let mut first_plugin_client = create_mock_openvpn_plugin_client(openvpn_args_file);
- let mut second_plugin_client = create_mock_openvpn_plugin_client(openvpn_args_file);
-
- let auth_result = first_plugin_client.authenticate();
- let call_result = second_plugin_client.up();
-
- assert_eq!(auth_result, Ok(true));
- assert!(call_result.is_err());
- assert_no_state_event(&state_events);
- assert_eq!(rpc_client.get_state().unwrap(), CONNECTING_STATE);
-}
-
-#[test]
fn changes_to_connected_state() {
let mut daemon = DaemonRunner::spawn();
let mut rpc_client = daemon.rpc_client().unwrap();
@@ -186,7 +101,6 @@ fn changes_to_connected_state() {
let mut mock_plugin_client = create_mock_openvpn_plugin_client(openvpn_args_file);
- mock_plugin_client.authenticate().unwrap();
mock_plugin_client.up().unwrap();
assert_state_event(&state_events, CONNECTED_STATE);
@@ -209,7 +123,6 @@ fn returns_to_connecting_state() {
let mut mock_plugin_client = create_mock_openvpn_plugin_client(openvpn_args_file);
- mock_plugin_client.authenticate().unwrap();
mock_plugin_client.up().unwrap();
assert_state_event(&state_events, CONNECTED_STATE);
@@ -240,14 +153,12 @@ fn disconnects() {
let mut mock_plugin_client = create_mock_openvpn_plugin_client(openvpn_args_file);
- mock_plugin_client.authenticate().unwrap();
mock_plugin_client.up().unwrap();
assert_state_event(&state_events, CONNECTED_STATE);
rpc_client.disconnect().unwrap();
- assert_state_event(&state_events, DISCONNECTING_STATE);
assert_state_event(&state_events, DISCONNECTED_STATE);
assert_eq!(rpc_client.get_state().unwrap(), DISCONNECTED_STATE);
}
@@ -260,33 +171,20 @@ fn assert_state_event(receiver: &mpsc::Receiver<DaemonState>, expected_state: Da
assert_eq!(received_state, expected_state);
}
-fn assert_no_state_event(receiver: &mpsc::Receiver<DaemonState>) {
- assert_eq!(
- receiver.recv_timeout(Duration::from_secs(1)),
- Err(mpsc::RecvTimeoutError::Timeout),
- );
-}
-
fn create_mock_openvpn_plugin_client<P: AsRef<Path>>(
openvpn_args_file_path: P,
) -> MockOpenVpnPluginRpcClient {
- let (address, credentials) = get_plugin_arguments(openvpn_args_file_path);
+ let address = get_plugin_arguments(openvpn_args_file_path);
- MockOpenVpnPluginRpcClient::new(address, credentials)
+ MockOpenVpnPluginRpcClient::new(address)
.expect("Failed to create mock RPC client to connect to OpenVPN plugin event listener")
}
-fn get_plugin_arguments<P: AsRef<Path>>(openvpn_args_file_path: P) -> (String, String) {
+fn get_plugin_arguments<P: AsRef<Path>>(openvpn_args_file_path: P) -> String {
let mut arguments = search_openvpn_args(openvpn_args_file_path, OPENVPN_PLUGIN_NAME).skip(1);
- let address = arguments
+ arguments
.next()
.expect("Missing OpenVPN plugin RPC listener address argument")
- .expect("Failed to read from mock OpenVPN arguments file");
- let credentials = arguments
- .next()
- .expect("Missing OpenVPN plugin RPC listener credentials argument")
- .expect("Failed to read from mock OpenVPN arguments file");
-
- (address, credentials)
+ .expect("Failed to read from mock OpenVPN arguments file")
}
diff --git a/mullvad-tests/tests/startup.rs b/mullvad-tests/tests/startup.rs
index 3bf47430cc..0424023515 100644
--- a/mullvad-tests/tests/startup.rs
+++ b/mullvad-tests/tests/startup.rs
@@ -4,39 +4,9 @@ extern crate mullvad_paths;
extern crate mullvad_tests;
extern crate mullvad_types;
-use std::fs::{self, Metadata};
-use std::io;
-use std::time::Duration;
-
-use mullvad_tests::{DaemonRunner, PathWatcher};
+use mullvad_tests::DaemonRunner;
use mullvad_types::states::{DaemonState, SecurityState, TargetState};
-use platform_specific::*;
-
-#[test]
-fn rpc_info_file_permissions() {
- let rpc_file = mullvad_paths::get_rpc_address_path().unwrap();
-
- if let Err(error) = fs::remove_file(&rpc_file) {
- if error.kind() != io::ErrorKind::NotFound {
- panic!("failed to remove existing RPC address file");
- }
- }
-
- assert!(!rpc_file.exists());
-
- let mut rpc_file_watcher = PathWatcher::watch(&rpc_file).unwrap();
- let _daemon = DaemonRunner::spawn_with_real_rpc_address_file();
-
- rpc_file_watcher.wait_for_burst_of_events(Duration::from_secs(10));
-
- assert!(rpc_file.exists());
-
- ensure_only_admin_can_write(
- fs::metadata(&rpc_file).expect("Failed to read RPC address file metadata"),
- );
-}
-
#[test]
fn starts_in_not_connected_state() {
let mut daemon = DaemonRunner::spawn();
@@ -50,26 +20,3 @@ fn starts_in_not_connected_state() {
assert_eq!(state, not_connected_state);
}
-
-#[cfg(unix)]
-mod platform_specific {
- extern crate libc;
-
- use super::*;
- use std::os::unix::fs::MetadataExt;
-
- pub fn ensure_only_admin_can_write(metadata: Metadata) {
- let process_uid = unsafe { libc::getuid() };
- assert_eq!(metadata.uid(), process_uid);
- assert_eq!(metadata.mode() & 0o022, 0);
- }
-}
-
-#[cfg(not(unix))]
-mod platform_specific {
- use super::*;
-
- pub fn ensure_only_admin_can_write(_metadata: Metadata) {
- // TODO: Test when correctly implemented on Windows
- }
-}
diff --git a/talpid-core/Cargo.toml b/talpid-core/Cargo.toml
index 52297f214d..23df76dfd8 100644
--- a/talpid-core/Cargo.toml
+++ b/talpid-core/Cargo.toml
@@ -10,8 +10,8 @@ atty = "0.2"
duct = "0.11"
error-chain = "0.12"
futures = "0.1"
-jsonrpc-core = { git = "https://github.com/paritytech/jsonrpc", tag = "v8.0.1" }
-jsonrpc-macros = { git = "https://github.com/paritytech/jsonrpc", tag = "v8.0.1" }
+jsonrpc-core = { git = "https://github.com/paritytech/jsonrpc", branch = "master" }
+jsonrpc-macros = { git = "https://github.com/paritytech/jsonrpc", branch = "master" }
libc = "0.2.20"
log = "0.4"
openvpn-plugin = { version = "0.3", features = ["serde"] }
diff --git a/talpid-core/src/tunnel/openvpn.rs b/talpid-core/src/tunnel/openvpn.rs
index c63429a4f5..8e89ed4a5c 100644
--- a/talpid-core/src/tunnel/openvpn.rs
+++ b/talpid-core/src/tunnel/openvpn.rs
@@ -12,7 +12,6 @@ use std::thread;
use std::time::Duration;
use talpid_ipc;
-use uuid;
mod errors {
error_chain!{
@@ -60,14 +59,10 @@ impl<C: OpenVpnBuilder> OpenVpnMonitor<C> {
L: Fn(OpenVpnPluginEvent, HashMap<String, String>) + Send + Sync + 'static,
P: AsRef<Path>,
{
- let credentials = uuid::Uuid::new_v4().to_string();
- let event_dispatcher = event_server::start(credentials.clone(), on_event)
- .chain_err(|| ErrorKind::EventDispatcherError)?;
+ let event_dispatcher =
+ event_server::start(on_event).chain_err(|| ErrorKind::EventDispatcherError)?;
- cmd.plugin(
- plugin_path,
- vec![event_dispatcher.address().to_owned(), credentials],
- );
+ cmd.plugin(plugin_path, vec![event_dispatcher.path().to_owned()]);
let child = cmd
.start()
.chain_err(|| ErrorKind::ChildProcessError("Failed to start"))?;
@@ -108,12 +103,9 @@ impl<C: OpenVpnBuilder> OpenVpnMonitor<C> {
error!("OpenVPN process wait error: {}", e);
Err(e).chain_err(|| ErrorKind::ChildProcessError("Error when waiting"))
}
- WaitResult::EventDispatcher(result) => {
- error!("OpenVPN Event server exited unexpectedly: {:?}", result);
- match result {
- Ok(()) => Err(ErrorKind::EventDispatcherError.into()),
- Err(e) => Err(e).chain_err(|| ErrorKind::EventDispatcherError),
- }
+ WaitResult::EventDispatcher => {
+ error!("OpenVPN Event server exited unexpectedly");
+ Err(ErrorKind::EventDispatcherError.into())
}
}
}
@@ -137,10 +129,8 @@ impl<C: OpenVpnBuilder> OpenVpnMonitor<C> {
dispatcher_handle.close();
});
thread::spawn(move || {
- let result = event_dispatcher.wait();
- dispatcher_tx
- .send(WaitResult::EventDispatcher(result))
- .unwrap();
+ event_dispatcher.wait();
+ dispatcher_tx.send(WaitResult::EventDispatcher).unwrap();
let _ = child_close_handle.close();
});
@@ -172,7 +162,7 @@ impl<H: ProcessHandle> OpenVpnCloseHandle<H> {
#[derive(Debug)]
enum WaitResult {
Child(io::Result<ExitStatus>, bool),
- EventDispatcher(talpid_ipc::Result<()>),
+ EventDispatcher,
}
/// Trait for types acting as OpenVPN process starters for `OpenVpnMonitor`.
@@ -221,41 +211,39 @@ impl ProcessHandle for OpenVpnProcHandle {
mod event_server {
use super::OpenVpnPluginEvent;
- use jsonrpc_core::{Compatibility, Error, MetaIoHandler, Metadata};
+ use jsonrpc_core::{Error, IoHandler, MetaIoHandler};
use std::collections::HashMap;
- use std::sync::atomic::{AtomicBool, Ordering};
- use std::sync::Arc;
use talpid_ipc;
+ use uuid;
/// Construct and start the IPC server with the given event listener callback.
- pub fn start<L>(credentials: String, on_event: L) -> talpid_ipc::Result<talpid_ipc::IpcServer>
+ pub fn start<L>(on_event: L) -> talpid_ipc::Result<talpid_ipc::IpcServer>
where
L: Fn(OpenVpnPluginEvent, HashMap<String, String>) + Send + Sync + 'static,
{
- let rpc = OpenVpnEventApiImpl {
- credentials,
- on_event,
+ let uuid = uuid::Uuid::new_v4().to_string();
+ let ipc_path = if cfg!(windows) {
+ format!("//./pipe/talpid-openvpn-{}", uuid)
+ } else {
+ format!("/tmp/talpid-openvpn-{}", uuid)
};
- let mut io = MetaIoHandler::with_compatibility(Compatibility::V2);
+ let rpc = OpenVpnEventApiImpl { on_event };
+ let mut io = IoHandler::new();
io.extend_with(rpc.to_delegate());
- talpid_ipc::IpcServer::start(io.into())
+ let meta_io: MetaIoHandler<()> = MetaIoHandler::from(io);
+ talpid_ipc::IpcServer::start(meta_io, ipc_path)
}
build_rpc_trait! {
pub trait OpenVpnEventApi {
- type Metadata;
-
- #[rpc(meta, name = "authenticate")]
- fn authenticate(&self, Self::Metadata, String) -> Result<bool, Error>;
- #[rpc(meta, name = "openvpn_event")]
- fn openvpn_event(&self, Self::Metadata, OpenVpnPluginEvent, HashMap<String, String>)
+ #[rpc(name = "openvpn_event")]
+ fn openvpn_event(&self, OpenVpnPluginEvent, HashMap<String, String>)
-> Result<(), Error>;
}
}
struct OpenVpnEventApiImpl<L> {
- credentials: String,
on_event: L,
}
@@ -263,60 +251,16 @@ mod event_server {
where
L: Fn(OpenVpnPluginEvent, HashMap<String, String>) + Send + Sync + 'static,
{
- type Metadata = Meta;
-
- fn authenticate(
- &self,
- metadata: Self::Metadata,
- credentials: String,
- ) -> Result<bool, Error> {
- if credentials == self.credentials {
- metadata.authenticated.store(true, Ordering::Relaxed);
- Ok(true)
- } else {
- Ok(false)
- }
- }
-
fn openvpn_event(
&self,
- metadata: Self::Metadata,
event: OpenVpnPluginEvent,
env: HashMap<String, String>,
) -> Result<(), Error> {
trace!("OpenVPN event {:?}", event);
- metadata.check_authentication()?;
(self.on_event)(event, env);
Ok(())
}
}
-
- #[derive(Clone)]
- struct Meta {
- authenticated: Arc<AtomicBool>,
- }
-
- impl Default for Meta {
- fn default() -> Self {
- Meta {
- authenticated: Arc::new(AtomicBool::new(false)),
- }
- }
- }
-
- impl Meta {
- fn check_authentication(&self) -> Result<(), Error> {
- if self.authenticated.load(Ordering::Relaxed) {
- trace!("Authenticated");
- Ok(())
- } else {
- trace!("Not authenticated");
- Err(Error::invalid_request())
- }
- }
- }
-
- impl Metadata for Meta {}
}
diff --git a/talpid-ipc/Cargo.toml b/talpid-ipc/Cargo.toml
index 591b0b1803..45848b45ca 100644
--- a/talpid-ipc/Cargo.toml
+++ b/talpid-ipc/Cargo.toml
@@ -10,13 +10,16 @@ error-chain = "0.12"
serde = "1.0"
serde_json = "1.0"
log = "0.4"
-jsonrpc-core = { git = "https://github.com/paritytech/jsonrpc", tag = "v8.0.1" }
-jsonrpc-pubsub = { git = "https://github.com/paritytech/jsonrpc", tag = "v8.0.1" }
-jsonrpc-ws-server = { git = "https://github.com/paritytech/jsonrpc", tag = "v8.0.1" }
-ws = { git = "https://github.com/tomusdrw/ws-rs" }
-url = "1.4"
+jsonrpc-core = { git = "https://github.com/paritytech/jsonrpc", branch = "master" }
+jsonrpc-pubsub = { git = "https://github.com/paritytech/jsonrpc", branch = "master" }
+jsonrpc-ipc-server = { git = "https://github.com/paritytech/jsonrpc", branch = "master" }
+jsonrpc-client-core = { git = "https://github.com/mullvad/jsonrpc-client-rs" }
+jsonrpc-client-ipc = { git = "https://github.com/mullvad/jsonrpc-client-rs" }
[dev-dependencies]
assert_matches = "1.0"
env_logger = "0.5"
-jsonrpc-macros = { git = "https://github.com/paritytech/jsonrpc", tag = "v8.0.1" }
+jsonrpc-macros = { git = "https://github.com/paritytech/jsonrpc", branch = "master" }
+uuid = { version = "0.6", features = ["v4"] }
+futures = "0.1.23"
+tokio-core = "0.1"
diff --git a/talpid-ipc/src/client.rs b/talpid-ipc/src/client.rs
deleted file mode 100644
index 63c95cc74f..0000000000
--- a/talpid-ipc/src/client.rs
+++ /dev/null
@@ -1,585 +0,0 @@
-use std::collections::HashMap;
-use std::sync::mpsc;
-use std::thread;
-
-use error_chain::ChainedError;
-use jsonrpc_pubsub::SubscriptionId;
-use serde;
-use serde_json::{self, Result as JsonResult, Value as JsonValue};
-use url::Url;
-use ws;
-
-type JsonMap = serde_json::map::Map<String, JsonValue>;
-
-mod errors {
- error_chain! {
- errors {
- ConnectError(details: &'static str) {
- description("Failed to connect to RPC server")
- display("Failed to connect to RPC server: {}", details)
- }
-
- ConnectionHandlerStopped {
- description("The WebSocket connection handler thread has stopped")
- }
-
- ErrorResponse(error_message: String) {
- description("Received an RPC error response")
- display("Received an RPC error response: {}", error_message)
- }
-
- DeserializeResponseError {
- description("Failed to deserialize response")
- }
-
- DeserializeSubscriptionEvent(event: String) {
- description("Failed to deserialize RPC subscription event")
- display("Failed to deserialize RPC subscription event {}", event)
- }
-
- ForwardSubscriptionEvent(event: String) {
- description("Failed to forward RPC subscription event")
- display("Failed to forward RPC subscription event {}", event)
- }
-
- InvalidJsonRpcResponse(details: &'static str) {
- description("Received an invalid JSON-RPC response")
- display("Received an invalid JSON-RPC response: {}", details)
- }
-
- InvalidServerIdUrl(server_id: ::IpcServerId) {
- description("Unable to parse given server ID as a URL")
- display("Unable to parse given server ID as a URL: {}", server_id)
- }
-
- InvalidSubscriptionEvent(details: &'static str) {
- description("Received an invalid JSON-RPC PubSub event")
- display("Received an invalid JSON-RPC PubSub event: {}", details)
- }
-
- InvalidSubscriptionId(raw_id: ::serde_json::Value) {
- description("Received an invalid JSON-RPC subscription ID for subscribe request")
- display(
- "Received an invalid JSON-RPC subscription ID for subscribe request: {}",
- raw_id,
- )
- }
-
- MissingResponse {
- description("No response received")
- }
-
- SendRequestError(method: String) {
- description("Failed to send a request to call a remote JSON-RPC procedure")
- display(
- "Failed to send a request to call the \"{}\" remote JSON-RPC procedure",
- method
- )
- }
-
- SerializeArgumentsError {
- description("Failed to serialize JSON-RPC request arguments")
- }
-
- SerializeSubscriptionId {
- description("Failed to serialize JSON-RPC subscription ID")
- }
-
- UnsubscribeError {
- description("Failed to unsubscribe from a remote event")
- }
-
- WebSocketError {
- description("Error with WebSocket connection")
- }
- }
- }
-}
-pub use self::errors::*;
-
-#[derive(Debug, Eq, PartialEq)]
-pub enum SubscriptionHandlerResult {
- Active,
- Finished,
-}
-
-type SubscriptionHandler = Box<Fn(JsonValue) -> SubscriptionHandlerResult + Send>;
-
-struct ActiveRequest {
- id: i64,
- response_tx: mpsc::Sender<Result<JsonValue>>,
-}
-
-impl ActiveRequest {
- pub fn new(id: i64, response_tx: mpsc::Sender<Result<JsonValue>>) -> Self {
- ActiveRequest { id, response_tx }
- }
-
- pub fn id(&self) -> i64 {
- self.id
- }
-
- pub fn send_response(&mut self, response: Result<JsonValue>) {
- let _ = self.response_tx.send(response);
- }
-}
-
-enum WsIpcCommand {
- Call {
- method: String,
- arguments: JsonValue,
- response_tx: mpsc::Sender<Result<JsonValue>>,
- },
-
- Subscribe {
- id: SubscriptionId,
- handler: SubscriptionHandler,
- unsubscribe_method: String,
- },
-
- Response {
- id: i64,
- result: Result<JsonValue>,
- },
-
- Notification {
- subscription: SubscriptionId,
- event: JsonValue,
- },
-
- Error(Error),
-}
-
-struct Factory {
- connection_tx: mpsc::Sender<WsIpcCommand>,
- sender_tx: mpsc::Sender<ws::Sender>,
-}
-
-impl ws::Factory for Factory {
- type Handler = Handler;
-
- fn connection_made(&mut self, sender: ws::Sender) -> Self::Handler {
- trace!("Connection established");
-
- let _ = self.sender_tx.send(sender);
-
- Handler {
- connection_tx: self.connection_tx.clone(),
- }
- }
-}
-
-
-struct Handler {
- connection_tx: mpsc::Sender<WsIpcCommand>,
-}
-
-impl Handler {
- fn process_message(&mut self, msg: ws::Message) -> Result<()> {
- trace!("WsIpcClient incoming message: {:?}", msg);
- let mut message_json_object = self.parse_message_object(msg)?;
- let response_id = self.parse_response_id(&mut message_json_object)?;
-
- let command = if let Some(id) = response_id {
- let result = self.parse_response_result(message_json_object);
-
- WsIpcCommand::Response { id, result }
- } else {
- let (subscription, event) = self.parse_subscription_event(message_json_object)?;
-
- WsIpcCommand::Notification {
- subscription,
- event,
- }
- };
-
- self.connection_tx
- .send(command)
- .chain_err(|| ErrorKind::ConnectionHandlerStopped)
- }
-
- fn parse_message_object(&self, msg: ws::Message) -> Result<JsonMap> {
- let parsed_json: JsonResult<JsonValue> = match msg {
- ws::Message::Text(s) => serde_json::from_str(&s),
- ws::Message::Binary(b) => serde_json::from_slice(&b),
- };
- let json = parsed_json.chain_err(|| {
- ErrorKind::InvalidJsonRpcResponse("Unable to deserialize ws message as JSON")
- })?;
-
- let mut json_object_map = match json {
- JsonValue::Object(object_map) => object_map,
- _ => bail!(ErrorKind::InvalidJsonRpcResponse(
- "Received response is not a JSON object"
- )),
- };
-
- ensure!(
- json_object_map.remove("jsonrpc") == Some(JsonValue::String("2.0".to_owned())),
- ErrorKind::InvalidJsonRpcResponse("Invalid JSON-RPC version field in response")
- );
-
- Ok(json_object_map)
- }
-
- fn parse_response_id(&self, json_object_map: &mut JsonMap) -> Result<Option<i64>> {
- match json_object_map.remove("id") {
- Some(JsonValue::Number(id)) => id.as_i64().map(Some).ok_or_else(|| {
- ErrorKind::InvalidJsonRpcResponse("Invalid request ID number").into()
- }),
- Some(_) => Err(ErrorKind::InvalidJsonRpcResponse("Invalid request ID value").into()),
- None => Ok(None),
- }
- }
-
- fn parse_response_result(&self, mut json_object_map: JsonMap) -> Result<JsonValue> {
- let result = json_object_map.remove("result");
- let error = json_object_map.remove("error");
-
- match (result, error) {
- (Some(remote_result), None) => Ok(remote_result),
- (None, Some(JsonValue::String(remote_error))) => {
- Err(ErrorKind::ErrorResponse(remote_error).into())
- }
- (None, Some(json_value)) => {
- Err(ErrorKind::ErrorResponse(json_value.to_string()).into())
- }
- (None, None) => Err(ErrorKind::InvalidJsonRpcResponse("Missing RPC result").into()),
- (Some(_), Some(_)) => Err(ErrorKind::InvalidJsonRpcResponse(
- "Response is ambiguous, contains both a successful result and an error",
- ).into()),
- }
- }
-
- fn parse_subscription_event(
- &mut self,
- mut notification: JsonMap,
- ) -> Result<(SubscriptionId, JsonValue)> {
- match notification.remove("params") {
- Some(JsonValue::Object(mut parameters)) => {
- let raw_id = parameters.remove("subscription").ok_or_else(|| {
- ErrorKind::InvalidSubscriptionEvent("Missing subscription ID")
- })?;
- let id = SubscriptionId::parse_value(&raw_id).ok_or_else(|| {
- ErrorKind::InvalidSubscriptionEvent("Invalid subscription ID")
- })?;
- let event = parameters
- .remove("result")
- .ok_or_else(|| ErrorKind::InvalidSubscriptionEvent("Missing event data"))?;
-
- Ok((id, event))
- }
- Some(_) => bail!(ErrorKind::InvalidSubscriptionEvent(
- "RPC parameters is not a JSON object map"
- )),
- None => bail!(ErrorKind::InvalidSubscriptionEvent(
- "Missing RPC parameters"
- )),
- }
- }
-}
-
-impl ws::Handler for Handler {
- fn on_message(&mut self, msg: ws::Message) -> ws::Result<()> {
- if let Err(error) = self.process_message(msg) {
- let chained_error = error.chain_err(|| "Failed to process RPC message");
- error!("{}", chained_error.display_chain());
- }
-
- Ok(())
- }
-
- fn on_error(&mut self, error: ws::Error) {
- let error = Error::with_chain(error, ErrorKind::WebSocketError);
-
- let _ = self.connection_tx.send(WsIpcCommand::Error(error));
- }
-}
-
-pub struct WsIpcClient {
- connection_tx: mpsc::Sender<WsIpcCommand>,
-}
-
-impl WsIpcClient {
- pub fn connect(server_id: &::IpcServerId) -> Result<Self> {
- let url = Url::parse(&server_id)
- .chain_err(|| ErrorKind::InvalidServerIdUrl(server_id.to_owned()))?;
- let (connection_tx, connection_rx) = mpsc::channel();
- let sender = Self::open_websocket(url, connection_tx.clone())?;
-
- WsIpcClientConnection::spawn(sender, connection_rx);
-
- Ok(WsIpcClient { connection_tx })
- }
-
- fn open_websocket(url: Url, connection_tx: mpsc::Sender<WsIpcCommand>) -> Result<ws::Sender> {
- let (sender_tx, sender_rx) = mpsc::channel();
- let factory = Factory {
- connection_tx,
- sender_tx,
- };
-
- let mut websocket = ws::WebSocket::new(factory)
- .chain_err(|| ErrorKind::ConnectError("Unable to create WebSocket"))?;
-
- websocket
- .connect(url)
- .chain_err(|| ErrorKind::ConnectError("Unable to connect WebSocket to URL"))?;
-
- thread::spawn(move || {
- let result = websocket
- .run()
- .chain_err(|| ErrorKind::ConnectError("Error while running WebSocket event loop"));
-
- if let Err(error) = result {
- error!("{}", error.display_chain());
- }
- });
-
- sender_rx
- .recv()
- .chain_err(|| ErrorKind::ConnectError("WebSocket connection failed"))
- }
-
- pub fn subscribe<V, M>(
- &mut self,
- subscribe_method: String,
- unsubscribe_method: String,
- sender: mpsc::Sender<M>,
- ) -> Result<()>
- where
- V: for<'de> serde::Deserialize<'de>,
- M: From<V> + Send + 'static,
- {
- let raw_subscription_id = self.call(&subscribe_method, &[] as &[u8; 0])?;
- let subscription_id = SubscriptionId::parse_value(&raw_subscription_id)
- .ok_or_else(|| ErrorKind::InvalidSubscriptionId(raw_subscription_id))?;
-
- let handler = move |json_value| match forward_subscription_event(
- &subscribe_method,
- json_value,
- &sender,
- ) {
- Ok(()) => SubscriptionHandlerResult::Active,
- Err(error) => {
- error!("{}", error.display_chain());
- SubscriptionHandlerResult::Finished
- }
- };
-
- self.register_subscription(subscription_id, handler, unsubscribe_method)?;
-
- Ok(())
- }
-
- fn register_subscription<H>(
- &mut self,
- id: SubscriptionId,
- handler: H,
- unsubscribe_method: String,
- ) -> Result<()>
- where
- H: Fn(JsonValue) -> SubscriptionHandlerResult + Send + 'static,
- {
- self.connection_tx
- .send(WsIpcCommand::Subscribe {
- id,
- handler: Box::new(handler),
- unsubscribe_method,
- }).chain_err(|| ErrorKind::ConnectionHandlerStopped)
- }
-
- pub fn call<S, T, O>(&mut self, method: S, params: &T) -> Result<O>
- where
- S: ToString,
- T: serde::Serialize,
- O: for<'de> serde::Deserialize<'de>,
- {
- let arguments =
- serde_json::to_value(params).chain_err(|| ErrorKind::SerializeArgumentsError)?;
- let (response_tx, response_rx) = mpsc::channel();
- let command = WsIpcCommand::Call {
- method: method.to_string(),
- arguments,
- response_tx,
- };
-
- self.connection_tx
- .send(command)
- .chain_err(|| ErrorKind::ConnectionHandlerStopped)?;
-
- let json_result = response_rx
- .recv()
- .chain_err(|| ErrorKind::MissingResponse)?;
-
- Ok(serde_json::from_value(json_result?)
- .chain_err(|| ErrorKind::DeserializeResponseError)?)
- }
-}
-
-struct WsIpcClientConnection {
- next_id: i64,
- active_request: Option<ActiveRequest>,
- active_subscriptions: HashMap<SubscriptionId, (SubscriptionHandler, String)>,
- sender: ws::Sender,
-}
-
-impl WsIpcClientConnection {
- pub fn spawn(sender: ws::Sender, commands: mpsc::Receiver<WsIpcCommand>) {
- let mut instance = WsIpcClientConnection {
- next_id: 1,
- active_request: None,
- active_subscriptions: HashMap::new(),
- sender,
- };
-
- thread::spawn(move || {
- if let Err(error) = instance.run(commands) {
- let chained_error = Error::with_chain(error, "WsIpcClient event loop error");
- error!("{}", chained_error.display_chain());
- }
- });
- }
-
- fn run(&mut self, commands: mpsc::Receiver<WsIpcCommand>) -> Result<()> {
- use self::WsIpcCommand::*;
-
- for command in commands {
- match command {
- Call {
- method,
- arguments,
- response_tx,
- } => self.call(method, arguments, response_tx)?,
- Subscribe {
- id,
- handler,
- unsubscribe_method,
- } => {
- self.active_subscriptions
- .insert(id, (handler, unsubscribe_method));
- }
- Response { id, result } => self.handle_response(id, result)?,
- Notification {
- subscription,
- event,
- } => self.handle_notification(subscription, event)?,
- Error(error) => self.handle_error(error),
- }
- }
-
- Ok(())
- }
-
- fn call(
- &mut self,
- method: String,
- arguments: JsonValue,
- response_tx: mpsc::Sender<Result<JsonValue>>,
- ) -> Result<()> {
- let id = self.new_id();
- self.queue_request_response(id, response_tx);
- self.send_request(id, method, arguments)
- }
-
- fn new_id(&mut self) -> i64 {
- let id = self.next_id;
- self.next_id += 1;
- id
- }
-
- fn queue_request_response(&mut self, id: i64, response_tx: mpsc::Sender<Result<JsonValue>>) {
- self.active_request = Some(ActiveRequest::new(id, response_tx));
- }
-
- fn send_request(&mut self, id: i64, method: String, arguments: JsonValue) -> Result<()> {
- let json_request = self.build_json_request(id, &method, arguments);
-
- self.sender
- .send(json_request.as_bytes())
- .chain_err(|| ErrorKind::SendRequestError(method))
- }
-
- fn build_json_request(&mut self, id: i64, method: &str, params: JsonValue) -> String {
- let request_json = json!({
- "jsonrpc": "2.0",
- "id": id,
- "method": method,
- "params": params,
- });
- format!("{}", request_json)
- }
-
- fn handle_response(&mut self, id: i64, result: Result<JsonValue>) -> Result<()> {
- if let Some(mut request) = self.active_request.take() {
- if request.id() == id {
- request.send_response(result);
- } else {
- self.active_request = Some(request);
- warn!("Received an unexpected response with ID {}", id);
- }
- } else {
- warn!("Received an unexpected response with ID {}", id);
- }
-
- Ok(())
- }
-
- fn handle_notification(&mut self, id: SubscriptionId, event: JsonValue) -> Result<()> {
- let unsubscribe_method =
- if let Some((handler, unsubscribe_method)) = self.active_subscriptions.get(&id) {
- match handler(event) {
- SubscriptionHandlerResult::Active => None,
- SubscriptionHandlerResult::Finished => Some(unsubscribe_method.clone()),
- }
- } else {
- warn!("Received an unexpected notification");
- None
- };
-
- if let Some(method) = unsubscribe_method {
- self.unsubscribe(method, id)?;
- }
-
- Ok(())
- }
-
- fn unsubscribe(&mut self, method: String, id: SubscriptionId) -> Result<()> {
- self.active_subscriptions.remove(&id);
-
- let (result_tx, _) = mpsc::channel();
- let arguments = match id {
- SubscriptionId::Number(id) => serde_json::to_value(&[id]),
- SubscriptionId::String(id) => serde_json::to_value(&[id]),
- }.chain_err(|| ErrorKind::SerializeSubscriptionId);
-
- self.call(method, arguments?, result_tx)
- .chain_err(|| ErrorKind::UnsubscribeError)
- }
-
- fn handle_error(&mut self, error: Error) {
- if let Some(ref mut request) = self.active_request {
- let _ = request.response_tx.send(Err(error));
- } else {
- error!("{}", error.display_chain());
- }
- }
-}
-
-fn forward_subscription_event<V, M>(
- subscribe_method: &String,
- json_value: JsonValue,
- sender: &mpsc::Sender<M>,
-) -> Result<()>
-where
- V: for<'de> serde::Deserialize<'de>,
- M: From<V> + Send + 'static,
-{
- let value: V = serde_json::from_value(json_value)
- .chain_err(|| ErrorKind::DeserializeSubscriptionEvent(subscribe_method.clone()))?;
- let message = M::from(value);
-
- sender
- .send(message)
- .chain_err(|| ErrorKind::ForwardSubscriptionEvent(subscribe_method.clone()))
-}
diff --git a/talpid-ipc/src/lib.rs b/talpid-ipc/src/lib.rs
index 4c6c737165..6104a59848 100644
--- a/talpid-ipc/src/lib.rs
+++ b/talpid-ipc/src/lib.rs
@@ -10,28 +10,22 @@
#[macro_use]
extern crate error_chain;
-#[macro_use]
-extern crate log;
extern crate serde;
-#[macro_use]
extern crate serde_json;
extern crate jsonrpc_core;
+extern crate jsonrpc_ipc_server;
extern crate jsonrpc_pubsub;
-extern crate jsonrpc_ws_server;
-extern crate url;
-extern crate ws;
-use jsonrpc_core::{MetaIoHandler, Metadata};
-use jsonrpc_ws_server::{MetaExtractor, NoopExtractor, Server, ServerBuilder};
+extern crate jsonrpc_client_core;
+extern crate jsonrpc_client_ipc;
-use std::fmt;
-use std::net::{IpAddr, Ipv4Addr, SocketAddr};
+use jsonrpc_core::{MetaIoHandler, Metadata};
+use jsonrpc_ipc_server::{MetaExtractor, NoopExtractor, SecurityAttributes, Server, ServerBuilder};
-mod client;
-pub use client::*;
+use std::fmt;
/// An Id created by the Ipc server that the client can use to connect to it
pub type IpcServerId = String;
@@ -41,38 +35,57 @@ error_chain!{
IpcServerError {
description("Error in IPC server")
}
+
+ PermissionsError {
+ description("Unable to set permissions for IPC endpoint")
+ }
}
}
pub struct IpcServer {
- address: String,
+ path: String,
server: Server,
}
impl IpcServer {
- pub fn start<M: Metadata>(handler: MetaIoHandler<M>) -> Result<Self> {
- Self::start_with_metadata(handler, NoopExtractor)
+ pub fn start<M: Metadata + Default>(handler: MetaIoHandler<M>, path: String) -> Result<Self> {
+ Self::start_with_metadata(handler, NoopExtractor, path)
}
- pub fn start_with_metadata<M, E>(handler: MetaIoHandler<M>, meta_extractor: E) -> Result<Self>
+ pub fn start_with_metadata<M, E>(
+ handler: MetaIoHandler<M>,
+ meta_extractor: E,
+ path: String,
+ ) -> Result<Self>
where
- M: Metadata,
+ M: Metadata + Default,
E: MetaExtractor<M>,
{
- let listen_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 0);
- ServerBuilder::new(handler)
- .session_meta_extractor(meta_extractor)
- .start(&listen_addr)
+ let security_attributes = SecurityAttributes::allow_everyone_create()
+ .chain_err(|| ErrorKind::PermissionsError)?;
+ let server = ServerBuilder::with_meta_extractor(handler, meta_extractor)
+ .set_security_attributes(security_attributes)
+ .start(&path)
+ .chain_err(|| ErrorKind::IpcServerError)
.map(|server| IpcServer {
- address: format!("ws://{}", server.addr()),
- server: server,
- }).chain_err(|| ErrorKind::IpcServerError)
+ path: path.to_owned(),
+ server,
+ })?;
+
+ #[cfg(unix)]
+ {
+ use std::fs;
+ use std::os::unix::fs::PermissionsExt;
+ fs::set_permissions(&path, PermissionsExt::from_mode(0o766))
+ .chain_err(|| ErrorKind::PermissionsError)?;
+ }
+ Ok(server)
}
- /// Returns the localhost address this `IpcServer` is listening on.
- pub fn address(&self) -> &str {
- &self.address
+ /// Returns the uds/named pipe path this `IpcServer` is listening on.
+ pub fn path(&self) -> &str {
+ &self.path
}
/// Creates a handle bound to this `IpcServer` that can be used to shut it down.
@@ -80,10 +93,10 @@ impl IpcServer {
CloseHandle(self.server.close_handle())
}
- /// Consumes the server and waits for it to finish. Get an `CloseHandle` before calling this
+ /// Consumes the server and waits for it to finish. Get a `CloseHandle` before calling this
/// if you want to be able to shut the server down.
- pub fn wait(self) -> Result<()> {
- self.server.wait().chain_err(|| ErrorKind::IpcServerError)
+ pub fn wait(self) {
+ self.server.wait();
}
}
@@ -92,14 +105,13 @@ impl IpcServer {
impl fmt::Debug for IpcServer {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("IpcServer")
- .field("address", &self.address)
+ .field("path", &self.path)
.finish()
}
}
-
#[derive(Clone)]
-pub struct CloseHandle(jsonrpc_ws_server::CloseHandle);
+pub struct CloseHandle(jsonrpc_ipc_server::CloseHandle);
impl CloseHandle {
pub fn close(self) {
diff --git a/talpid-ipc/tests/ipc-client-server.rs b/talpid-ipc/tests/ipc-client-server.rs
index 34b44beb68..dc5c8d9d17 100644
--- a/talpid-ipc/tests/ipc-client-server.rs
+++ b/talpid-ipc/tests/ipc-client-server.rs
@@ -1,11 +1,22 @@
#[macro_use]
extern crate assert_matches;
extern crate env_logger;
+extern crate jsonrpc_client_core;
+extern crate jsonrpc_client_ipc;
extern crate jsonrpc_core;
#[macro_use]
extern crate jsonrpc_macros;
extern crate talpid_ipc;
+extern crate tokio_core;
+extern crate uuid;
+extern crate futures;
+
+use futures::sync::oneshot;
+use futures::Future;
+use tokio_core::reactor::Core;
+
+use jsonrpc_client_core::{Error as ClientError, Transport};
use jsonrpc_core::{Error, IoHandler};
use std::sync::{mpsc, Mutex};
use std::time::Duration;
@@ -35,13 +46,13 @@ fn can_call_rpcs_on_server() {
env_logger::init();
let (server, rx) = create_server();
- let server_id = server.address().to_owned();
- let mut client = create_client(&server_id);
+ let server_path = server.path().to_owned();
+ let client = create_client(server_path);
- let _result: () = client.call("foo", &[97]).unwrap();
+ let _result: () = client.call_method("foo", &[97]).wait().unwrap();
assert_eq!(Ok(97), rx.recv_timeout(Duration::from_millis(500)));
- let result: Result<(), _> = client.call("invalid_method", &[0]);
+ let result: Result<(), ClientError> = client.call_method("invalid_method", &[0]).wait();
assert_matches!(result, Err(_));
server.close_handle().close();
}
@@ -51,14 +62,7 @@ fn can_call_rpcs_on_server() {
#[test]
#[should_panic]
fn ipc_client_invalid_url() {
- create_client(&"INVALID ID".to_owned());
-}
-
-#[test]
-fn ipc_client_bad_connection() {
- let mut client = create_client(&"ws://127.0.0.1:9876".to_owned());
- let result: Result<(), _> = client.call("invalid_method", &[0]);
- assert_matches!(result, Err(_));
+ let _client = create_client("INVALID ID".to_owned());
}
fn create_server() -> (talpid_ipc::IpcServer, mpsc::Receiver<i64>) {
@@ -67,10 +71,30 @@ fn create_server() -> (talpid_ipc::IpcServer, mpsc::Receiver<i64>) {
let mut io = IoHandler::new();
io.extend_with(rpc.to_delegate());
- let server = talpid_ipc::IpcServer::start(io.into()).unwrap();
+ let uuid = uuid::Uuid::new_v4().to_string();
+ let ipc_path = if cfg!(windows) {
+ format!(r"\\.\pipe\ipc-test-{}", uuid)
+ } else {
+ format!("/tmp/ipc-test-{}", uuid)
+ };
+ let server = talpid_ipc::IpcServer::start(io.into(), ipc_path).unwrap();
(server, rx)
}
-fn create_client(id: &talpid_ipc::IpcServerId) -> talpid_ipc::WsIpcClient {
- talpid_ipc::WsIpcClient::connect(id).unwrap()
+fn create_client(ipc_path: String) -> jsonrpc_client_core::ClientHandle {
+ use std::thread;
+ let (tx, rx) = oneshot::channel();
+
+ thread::spawn(move || {
+ let mut core = Core::new().expect("failed to spawn reactor");
+ let (client, client_handle) =
+ jsonrpc_client_ipc::IpcTransport::new(&ipc_path, &core.handle())
+ .expect("failed to construct a transport")
+ .into_client();
+ tx.send(client_handle).unwrap();
+ core.run(client).unwrap();
+ });
+
+ let handle = rx.wait().expect("Failed to construct a valid client");
+ handle
}
diff --git a/talpid-openvpn-plugin/Cargo.toml b/talpid-openvpn-plugin/Cargo.toml
index c5987d68ef..165a4976be 100644
--- a/talpid-openvpn-plugin/Cargo.toml
+++ b/talpid-openvpn-plugin/Cargo.toml
@@ -12,9 +12,14 @@ crate-type = ["cdylib"]
error-chain = "0.12"
log = "0.4"
env_logger = "0.5"
+jsonrpc-client-core = { git = "https://github.com/mullvad/jsonrpc-client-rs" }
+jsonrpc-client-ipc = { git = "https://github.com/mullvad/jsonrpc-client-rs" }
+tokio-core = "0.1"
+futures = "0.1"
openvpn-plugin = { version = "0.3", features = ["serde", "log"] }
talpid-ipc = { path = "../talpid-ipc" }
+
[target.'cfg(windows)'.build-dependencies]
windres = "0.2"
diff --git a/talpid-openvpn-plugin/src/lib.rs b/talpid-openvpn-plugin/src/lib.rs
index 9c6c690339..ed358a5df7 100644
--- a/talpid-openvpn-plugin/src/lib.rs
+++ b/talpid-openvpn-plugin/src/lib.rs
@@ -13,12 +13,19 @@ extern crate error_chain;
extern crate log;
#[macro_use]
+extern crate jsonrpc_client_core;
+extern crate futures;
+extern crate jsonrpc_client_ipc;
+#[macro_use]
extern crate openvpn_plugin;
-extern crate talpid_ipc;
+extern crate tokio_core;
+use error_chain::ChainedError;
use openvpn_plugin::types::{EventResult, OpenVpnPluginEvent};
use std::collections::HashMap;
use std::ffi::CString;
+use std::sync::Mutex;
+
mod processing;
use processing::EventProcessor;
@@ -54,26 +61,28 @@ openvpn_plugin!(
::openvpn_open,
::openvpn_close,
::openvpn_event,
- ::EventProcessor
+ ::Mutex<EventProcessor>
);
pub struct Arguments {
- server_id: talpid_ipc::IpcServerId,
- credentials: String,
+ ipc_socket_path: String,
}
fn openvpn_open(
args: Vec<CString>,
_env: HashMap<CString, CString>,
-) -> Result<(Vec<OpenVpnPluginEvent>, EventProcessor)> {
+) -> Result<(Vec<OpenVpnPluginEvent>, Mutex<EventProcessor>)> {
env_logger::init();
debug!("Initializing plugin");
let arguments = parse_args(&args)?;
- info!("Connecting back to talpid core at {}", arguments.server_id);
- let processor = EventProcessor::new(&arguments).chain_err(|| ErrorKind::InitHandleFailed)?;
+ info!(
+ "Connecting back to talpid core at {}",
+ arguments.ipc_socket_path
+ );
+ let processor = EventProcessor::new(arguments).chain_err(|| ErrorKind::InitHandleFailed)?;
- Ok((INTERESTING_EVENTS.to_vec(), processor))
+ Ok((INTERESTING_EVENTS.to_vec(), Mutex::new(processor)))
}
fn parse_args(args: &[CString]) -> Result<Arguments> {
@@ -82,37 +91,39 @@ fn parse_args(args: &[CString]) -> Result<Arguments> {
.into_iter();
let _plugin_path = args_iter.next();
- let server_id: talpid_ipc::IpcServerId = args_iter
+ let ipc_socket_path: String = args_iter
.next()
.ok_or_else(|| ErrorKind::Msg("No core server id given as first argument".to_owned()))?;
- let credentials = args_iter
- .next()
- .ok_or_else(|| ErrorKind::Msg("No IPC credentials given as second argument".to_owned()))?;
- Ok(Arguments {
- server_id,
- credentials,
- })
+ Ok(Arguments { ipc_socket_path })
}
-fn openvpn_close(_handle: EventProcessor) {
- debug!("Unloading plugin");
+fn openvpn_close(_handle: Mutex<EventProcessor>) {
+ info!("Unloading plugin");
}
fn openvpn_event(
event: OpenVpnPluginEvent,
_args: Vec<CString>,
env: HashMap<CString, CString>,
- handle: &mut EventProcessor,
+ handle: &mut Mutex<EventProcessor>,
) -> Result<EventResult> {
debug!("Received event: {:?}", event);
let parsed_env =
openvpn_plugin::ffi::parse::env_utf8(&env).chain_err(|| ErrorKind::ParseEnvFailed)?;
- handle
+ let result = handle
+ .lock()
+ .expect("failed to obtain mutex for EventProcessor")
.process_event(event, parsed_env)
- .chain_err(|| ErrorKind::EventProcessingFailed)?;
- Ok(EventResult::Success)
+ .chain_err(|| ErrorKind::EventProcessingFailed);
+ match result {
+ Ok(()) => Ok(EventResult::Success),
+ Err(e) => {
+ error!("{}", e.display_chain());
+ Ok(EventResult::Failure)
+ }
+ }
}
diff --git a/talpid-openvpn-plugin/src/processing.rs b/talpid-openvpn-plugin/src/processing.rs
index 99533945ed..66d009b44f 100644
--- a/talpid-openvpn-plugin/src/processing.rs
+++ b/talpid-openvpn-plugin/src/processing.rs
@@ -1,42 +1,55 @@
use openvpn_plugin;
use std::collections::HashMap;
-use std::sync::Mutex;
-use talpid_ipc::WsIpcClient;
+
+extern crate futures;
+
+use jsonrpc_client_core::{Future, Result as ClientResult, Transport};
+use jsonrpc_client_ipc::IpcTransport;
+use tokio_core::reactor::Core;
use super::Arguments;
error_chain! {
errors {
- AuthDenied {
- description("Failed to authenticate with Talpid IPC server")
- }
IpcSendingError {
description("Failed while sending an event over the IPC channel")
}
+
+ Shutdown {
+ description("Connection is shut down")
+ }
+
}
}
/// Struct processing OpenVPN events and notifies listeners over IPC
pub struct EventProcessor {
- ipc_client: Mutex<WsIpcClient>,
+ ipc_client: EventProxy,
+ client_stop: ::std::sync::mpsc::Receiver<ClientResult<()>>,
+ core: Core,
}
impl EventProcessor {
- pub fn new(arguments: &Arguments) -> Result<EventProcessor> {
+ pub fn new(arguments: Arguments) -> Result<EventProcessor> {
trace!("Creating EventProcessor");
- let mut ipc_client = WsIpcClient::connect(&arguments.server_id)
- .chain_err(|| "Unable to create IPC client")?;
+ let core = Core::new().chain_err(|| "Unable to initialize Tokio Core")?;
+ let handle = core.handle();
+ let (client, client_handle) = IpcTransport::new(&arguments.ipc_socket_path, &handle)
+ .chain_err(|| "Unable to create IPC transport")?
+ .into_client();
- trace!("Authenticating EventProcessor");
- match ipc_client.call("authenticate", &[&arguments.credentials]) {
- Ok(true) => trace!("Credentials accepted"),
- Ok(false) => bail!(ErrorKind::AuthDenied),
- Err(error) => bail!(Error::with_chain(error, ErrorKind::AuthDenied)),
- }
+ let (tx, client_stop) = ::std::sync::mpsc::channel();
+
+ let client_future = client.then(move |result| tx.send(result)).map_err(|_| ());
+ handle.spawn(client_future);
+
+ let ipc_client = EventProxy::new(client_handle);
Ok(EventProcessor {
- ipc_client: Mutex::new(ipc_client),
+ ipc_client,
+ client_stop,
+ core,
})
}
@@ -46,11 +59,25 @@ impl EventProcessor {
env: HashMap<String, String>,
) -> Result<()> {
trace!("Processing \"{:?}\" event", event);
- self.ipc_client
- .lock()
- .expect("a thread panicked while using the RPC client in the OpenVPN plugin")
- .call("openvpn_event", &(event, env))
- .map(|_: Option<()>| ())
- .chain_err(|| ErrorKind::IpcSendingError)
+ let call_future = self
+ .ipc_client
+ .openvpn_event(event, env)
+ .map_err(|e| Error::with_chain(e, ErrorKind::IpcSendingError));
+ self.core.run(call_future)?;
+ self.check_client_status()
+ }
+
+ fn check_client_status(&mut self) -> Result<()> {
+ use std::sync::mpsc::TryRecvError::*;
+ match self.client_stop.try_recv() {
+ Err(Empty) => Ok(()),
+ Err(Disconnected) => Err(ErrorKind::Shutdown.into()),
+ Ok(Ok(_)) => Err(ErrorKind::Shutdown.into()),
+ Ok(Err(e)) => Err(Error::with_chain(e, ErrorKind::IpcSendingError)),
+ }
}
}
+
+jsonrpc_client!(pub struct EventProxy {
+ pub fn openvpn_event(&mut self, event: openvpn_plugin::types::OpenVpnPluginEvent, env: HashMap<String, String>) -> Future<()>;
+});