summaryrefslogtreecommitdiffhomepage
path: root/tunnel
diff options
context:
space:
mode:
Diffstat (limited to 'tunnel')
-rw-r--r--tunnel/build.gradle53
-rw-r--r--tunnel/src/main/java/com/wireguard/android/backend/GoBackend.java32
-rw-r--r--tunnel/src/main/java/com/wireguard/android/backend/LocalSocketAdapter.java325
-rw-r--r--tunnel/src/main/java/com/wireguard/android/backend/UnixDomainSocketFactory.java59
-rw-r--r--tunnel/src/main/proto/libwg.proto27
-rw-r--r--tunnel/tools/libwg-go/.gitignore3
-rw-r--r--tunnel/tools/libwg-go/Makefile27
-rw-r--r--tunnel/tools/libwg-go/api-android.go29
-rw-r--r--tunnel/tools/libwg-go/jni.c13
-rw-r--r--tunnel/tools/libwg-go/service.go76
10 files changed, 637 insertions, 7 deletions
diff --git a/tunnel/build.gradle b/tunnel/build.gradle
index 54ef4d91..8ca93050 100644
--- a/tunnel/build.gradle
+++ b/tunnel/build.gradle
@@ -1,5 +1,12 @@
+buildscript {
+ dependencies {
+ classpath "com.google.protobuf:protobuf-gradle-plugin:$protobufGradleVersion"
+ }
+}
+
plugins {
id 'com.android.library'
+ id 'com.google.protobuf' version "$protobufGradleVersion"
}
version wireguardVersionName
@@ -52,8 +59,54 @@ android {
dependencies {
implementation "androidx.annotation:annotation:$annotationsVersion"
implementation "androidx.collection:collection:$collectionVersion"
+ implementation "io.grpc:grpc-okhttp:$grpcVersion"
+ implementation "io.grpc:grpc-protobuf-lite:$grpcVersion"
+ implementation "io.grpc:grpc-stub:$grpcVersion"
compileOnly "com.google.code.findbugs:jsr305:$jsr305Version"
+ compileOnly "javax.annotation:javax.annotation-api:1.2"
testImplementation "junit:junit:$junitVersion"
}
+protobuf {
+ protoc {
+ // You still need protoc like in the non-Android case
+ artifact = "com.google.protobuf:protoc:$protocVersion"
+ }
+ plugins {
+ grpc {
+ artifact = "io.grpc:protoc-gen-grpc-java:$grpcVersion"
+ }
+ }
+ generateProtoTasks {
+ all().each { task ->
+ task.builtins {
+ java {
+ option 'lite'
+ }
+ }
+ task.plugins {
+ grpc {
+ option 'lite'
+ }
+ }
+ }
+ }
+}
+
+afterEvaluate({ project ->
+ // All custom configurations created by the protobuf plugin,
+ // are only available at this point.
+ def protoc = configurations.getByName('protobufToolsLocator_protoc')
+
+ task copyProtoc(type: Copy) {
+ // Used by tunnel/tools/libwg-go/Makefile run in tools/CMakeLists.txt
+ from protoc
+ into "${gradle.gradleUserHomeDir}/caches/protoc-${protocVersion}"
+ rename 'protoc-.*', 'protoc'
+ fileMode 0775
+ }
+
+ preBuild.dependsOn copyProtoc
+})
+
apply from: "publish.gradle"
diff --git a/tunnel/src/main/java/com/wireguard/android/backend/GoBackend.java b/tunnel/src/main/java/com/wireguard/android/backend/GoBackend.java
index 00a528f2..f10ddc52 100644
--- a/tunnel/src/main/java/com/wireguard/android/backend/GoBackend.java
+++ b/tunnel/src/main/java/com/wireguard/android/backend/GoBackend.java
@@ -7,14 +7,22 @@ package com.wireguard.android.backend;
import android.content.Context;
import android.content.Intent;
+import android.net.LocalSocketAddress;
import android.net.ProxyInfo;
import android.os.Build;
import android.os.ParcelFileDescriptor;
import android.system.OsConstants;
import android.util.Log;
+import com.google.protobuf.ByteString;
+import com.google.protobuf.InvalidProtocolBufferException;
+import com.google.protobuf.Empty;
+
import com.wireguard.android.backend.BackendException.Reason;
import com.wireguard.android.backend.Tunnel.State;
+import com.wireguard.android.backend.gen.LibwgGrpc;
+import com.wireguard.android.backend.gen.VersionRequest;
+import com.wireguard.android.backend.gen.VersionResponse;
import com.wireguard.android.util.SharedLibraryLoader;
import com.wireguard.config.Config;
import com.wireguard.config.InetEndpoint;
@@ -24,6 +32,11 @@ import com.wireguard.crypto.Key;
import com.wireguard.crypto.KeyFormatException;
import com.wireguard.util.NonNullForAll;
+import io.grpc.ManagedChannel;
+import io.grpc.ManagedChannelBuilder;
+import io.grpc.okhttp.OkHttpChannelBuilder;
+
+import java.io.File;
import java.net.InetAddress;
import java.net.URL;
import java.util.Collections;
@@ -34,6 +47,8 @@ import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
+import javax.net.SocketFactory;
+
import androidx.annotation.Nullable;
import androidx.collection.ArraySet;
@@ -51,6 +66,7 @@ public final class GoBackend implements Backend {
@Nullable private Config currentConfig;
@Nullable private Tunnel currentTunnel;
private int currentTunnelHandle = -1;
+ private ManagedChannel channel;
/**
* Public constructor for GoBackend.
@@ -60,6 +76,15 @@ public final class GoBackend implements Backend {
public GoBackend(final Context context) {
SharedLibraryLoader.loadSharedLibrary(context, "wg-go");
this.context = context;
+
+ File socketFile = new File(context.getCacheDir(), "libwg.sock");
+ String socketName = socketFile.getAbsolutePath();
+ Log.i(TAG, "wgStartGrpc: " + wgStartGrpc(socketName));
+ ManagedChannelBuilder<?> channelBuilder = ManagedChannelBuilder.forAddress("localhost", 10000).usePlaintext();
+ LocalSocketAddress address = new LocalSocketAddress(socketName, LocalSocketAddress.Namespace.FILESYSTEM);
+ SocketFactory socketFactory = new UnixDomainSocketFactory(address);
+ ((OkHttpChannelBuilder) channelBuilder).socketFactory(socketFactory);
+ channel = channelBuilder.build();
}
/**
@@ -84,6 +109,8 @@ public final class GoBackend implements Backend {
private static native String wgVersion();
+ private static native int wgStartGrpc(String sockName);
+
/**
* Method to get the names of running tunnels.
*
@@ -168,7 +195,10 @@ public final class GoBackend implements Backend {
*/
@Override
public String getVersion() {
- return wgVersion();
+ LibwgGrpc.LibwgBlockingStub stub = LibwgGrpc.newBlockingStub(channel);
+ VersionRequest request = VersionRequest.newBuilder().build();
+ VersionResponse resp = stub.version(request);
+ return resp.getVersion();
}
/**
diff --git a/tunnel/src/main/java/com/wireguard/android/backend/LocalSocketAdapter.java b/tunnel/src/main/java/com/wireguard/android/backend/LocalSocketAdapter.java
new file mode 100644
index 00000000..bf027ae1
--- /dev/null
+++ b/tunnel/src/main/java/com/wireguard/android/backend/LocalSocketAdapter.java
@@ -0,0 +1,325 @@
+/*
+ */
+package com.wireguard.android.backend;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.net.SocketAddress;
+import java.net.SocketException;
+import java.net.SocketImplFactory;
+import java.net.SocketOptions;
+import java.nio.channels.SocketChannel;
+import java.util.Vector;
+import android.net.LocalSocket;
+import android.net.LocalSocketAddress;
+import android.util.Log;
+
+/**
+ * Adaptor allows using a LocalSocket as a Socket.
+ */
+final class LocalSocketAdapter extends Socket {
+ private final LocalSocketAddress address;
+ private final LocalSocket unix;
+ private final SocketAddress localAddress;
+ private InetSocketAddress inetSocketAddress;
+ private InputStream is;
+ private OutputStream os;
+
+ LocalSocketAdapter(LocalSocketAddress address) {
+ this.address = address;
+ this.localAddress = new InetSocketAddress(0);
+ unix = new LocalSocket();
+ }
+
+ LocalSocketAdapter(LocalSocketAddress address, InetSocketAddress inetAddress) {
+ this(address);
+ this.inetSocketAddress = inetAddress;
+ }
+
+ private void throwUnsupportedOperationException() {
+ Log.i("helloworld", "Unsupported: " + Log.getStackTraceString(new Exception()));
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void bind (SocketAddress bindpoint) {
+ throwUnsupportedOperationException();
+ }
+
+ @Override
+ public void close() throws IOException {
+ unix.close();
+ }
+
+ @Override public void connect(SocketAddress endpoint) throws IOException {
+ this.inetSocketAddress = (InetSocketAddress) endpoint;
+ try {
+ unix.connect(address);
+ } catch (IOException e) {
+ Log.i("helloworld", "Error: " + e.toString());
+ throw e;
+ }
+ }
+
+ @Override
+ public void connect(SocketAddress endpoint, int timeout) throws IOException {
+ this.inetSocketAddress = (InetSocketAddress) endpoint;
+ unix.connect(address, timeout);
+ }
+
+ @Override
+ public SocketChannel getChannel() {
+ throwUnsupportedOperationException();
+ return null;
+ }
+
+ @Override public InetAddress getInetAddress() {
+ return inetSocketAddress.getAddress();
+ }
+
+ @Override
+ public InputStream getInputStream() throws IOException {
+ is = unix.getInputStream();
+ return is;
+ }
+
+ @Override
+ public boolean getKeepAlive() {
+ throwUnsupportedOperationException();
+ return false;
+ }
+
+ @Override
+ public InetAddress getLocalAddress() {
+ throwUnsupportedOperationException();
+ return null;
+ }
+
+ @Override
+ public int getLocalPort() {
+ throwUnsupportedOperationException();
+ return 0;
+ }
+
+ @Override
+ public SocketAddress getLocalSocketAddress() {
+ //throwUnsupportedOperationException();
+ return localAddress;
+ }
+
+ @Override
+ public boolean getOOBInline() {
+ throwUnsupportedOperationException();
+ return false;
+ }
+
+ @Override
+ public OutputStream getOutputStream() throws IOException {
+ if (os != null)
+ return os;
+
+ OutputStream unixOs = unix.getOutputStream();
+ os = new OutputStream() {
+ @Override
+ public void close() throws IOException {
+ // LocalSocket's default implementation closes the socket,
+ // which leaves readers of thes InputStream hanging.
+ // Instead shutdown input (and output) to release readers.
+ LocalSocketAdapter.this.shutdownInput();
+ LocalSocketAdapter.this.shutdownOutput();
+ }
+
+ @Override
+ public void write (byte[] b) throws IOException {
+ unixOs.write(b);
+ }
+
+ @Override
+ public void write (byte[] b, int off, int len) throws IOException {
+ unixOs.write(b, off, len);
+ }
+
+ @Override
+ public void write (int b) throws IOException {
+ unixOs.write(b);
+ }
+ };
+ return os;
+ }
+
+ @Override
+ public int getPort() {
+ return inetSocketAddress.getPort();
+ }
+
+ @Override
+ public int getReceiveBufferSize() throws SocketException {
+ try {
+ return unix.getReceiveBufferSize();
+ } catch (IOException e) {
+ throw new SocketException(e.getMessage());
+ }
+ }
+
+ @Override
+ public SocketAddress getRemoteSocketAddress() {
+ return inetSocketAddress;
+ }
+
+ @Override
+ public boolean getReuseAddress() {
+ throwUnsupportedOperationException();
+ return false;
+ }
+
+ @Override
+ public int getSendBufferSize() throws SocketException {
+ try {
+ return unix.getSendBufferSize();
+ } catch (IOException e) {
+ throw new SocketException(e.getMessage());
+ }
+ }
+
+ @Override
+ public int getSoLinger() {
+ throwUnsupportedOperationException();
+ return 0;
+ }
+
+ @Override
+ public int getSoTimeout() throws SocketException {
+ try {
+ return unix.getSoTimeout();
+ } catch (IOException e) {
+ throw new SocketException(e.getMessage());
+ }
+ }
+
+ @Override
+ public boolean getTcpNoDelay() {
+ throwUnsupportedOperationException();
+ return false;
+ }
+
+ @Override
+ public int getTrafficClass() {
+ throwUnsupportedOperationException();
+ return 0;
+ }
+
+ @Override
+ public boolean isBound() {
+ return unix.isBound();
+ }
+
+ @Override
+ public boolean isClosed() {
+ return unix.isClosed();
+ }
+
+ @Override
+ public boolean isConnected() {
+ return unix.isConnected();
+ }
+
+ @Override
+ public boolean isInputShutdown() {
+ return unix.isInputShutdown();
+ }
+
+ @Override
+ public boolean isOutputShutdown() {
+ return unix.isOutputShutdown();
+ }
+
+ @Override
+ public void sendUrgentData (int data) {
+ throwUnsupportedOperationException();
+ }
+
+ @Override
+ public void setKeepAlive (boolean on) {
+ throwUnsupportedOperationException();
+ }
+
+ @Override
+ public void setOOBInline (boolean on) {
+ throwUnsupportedOperationException();
+ }
+
+ @Override
+ public void setPerformancePreferences (int connectionTime,
+ int latency,
+ int bandwidth) {
+ throwUnsupportedOperationException();
+ }
+
+ @Override
+ public void setReceiveBufferSize(int size) throws SocketException {
+ try {
+ unix.setReceiveBufferSize(size);
+ } catch (IOException e) {
+ throw new SocketException(e.getMessage());
+ }
+ }
+
+ @Override
+ public void setReuseAddress (boolean on) {
+ throwUnsupportedOperationException();
+ }
+
+ @Override
+ public void setSendBufferSize(int size) throws SocketException {
+ try {
+ unix.setSendBufferSize(size);
+ } catch (IOException e) {
+ throw new SocketException(e.getMessage());
+ }
+ }
+
+ @Override
+ public void setSoLinger (boolean on,
+ int linger) {
+ throwUnsupportedOperationException();
+ }
+
+ @Override
+ public void setSoTimeout(int timeout) throws SocketException {
+ try {
+ unix.setSoTimeout(timeout);
+ } catch (IOException e) {
+ throw new SocketException(e.getMessage());
+ }
+ }
+
+ @Override
+ public void setTcpNoDelay (boolean on) {
+ // Not relevant for local sockets.
+ }
+
+ @Override
+ public void setTrafficClass (int tc) {
+ throwUnsupportedOperationException();
+ }
+
+ @Override
+ public void shutdownInput() throws IOException {
+ unix.shutdownInput();
+ }
+
+ @Override
+ public void shutdownOutput() throws IOException {
+ unix.shutdownOutput();
+ }
+
+ @Override
+ public String toString() {
+ return unix.toString();
+ }
+}
diff --git a/tunnel/src/main/java/com/wireguard/android/backend/UnixDomainSocketFactory.java b/tunnel/src/main/java/com/wireguard/android/backend/UnixDomainSocketFactory.java
new file mode 100644
index 00000000..427a19f1
--- /dev/null
+++ b/tunnel/src/main/java/com/wireguard/android/backend/UnixDomainSocketFactory.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2018 Square, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.wireguard.android.backend;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import javax.net.SocketFactory;
+import android.net.LocalSocketAddress;
+
+/** Impersonate TCP-style SocketFactory over UNIX domain sockets. */
+public final class UnixDomainSocketFactory extends SocketFactory {
+ private final LocalSocketAddress address;
+
+ public UnixDomainSocketFactory(LocalSocketAddress address) {
+ this.address = address;
+ }
+
+ @Override public Socket createSocket() throws IOException {
+ return new LocalSocketAdapter(address);
+ }
+
+ @Override public Socket createSocket(String host, int port) throws IOException {
+ Socket result = createSocket();
+ result.connect(new InetSocketAddress(host, port));
+ return result;
+ }
+
+ @Override public Socket createSocket(
+ String host, int port, InetAddress localHost, int localPort) throws IOException {
+ return createSocket(host, port);
+ }
+
+ @Override public Socket createSocket(InetAddress host, int port) throws IOException {
+ Socket result = createSocket();
+ result.connect(new InetSocketAddress(host, port));
+ return result;
+ }
+
+ @Override public Socket createSocket(
+ InetAddress host, int port, InetAddress localAddress, int localPort) throws IOException {
+ return createSocket(host, port);
+ }
+}
diff --git a/tunnel/src/main/proto/libwg.proto b/tunnel/src/main/proto/libwg.proto
new file mode 100644
index 00000000..2d964897
--- /dev/null
+++ b/tunnel/src/main/proto/libwg.proto
@@ -0,0 +1,27 @@
+syntax = "proto3";
+
+option java_multiple_files = true;
+option java_package = 'com.wireguard.android.backend.gen';
+option java_outer_classname = "LibwgProto";
+option java_generic_services = true;
+option go_package = 'golang.zx2c4.com/wireguard/android/gen';
+
+package api;
+
+service Libwg {
+ rpc StopGrpc(StopGrpcRequest) returns (StopGrpcResponse);
+ rpc Version(VersionRequest) returns (VersionResponse);
+}
+
+message StopGrpcRequest {
+}
+
+message StopGrpcResponse {
+}
+
+message VersionRequest {
+}
+
+message VersionResponse {
+ string version = 1;
+}
diff --git a/tunnel/tools/libwg-go/.gitignore b/tunnel/tools/libwg-go/.gitignore
index d1638636..d69ee823 100644
--- a/tunnel/tools/libwg-go/.gitignore
+++ b/tunnel/tools/libwg-go/.gitignore
@@ -1 +1,2 @@
-build/ \ No newline at end of file
+build/
+/gen/
diff --git a/tunnel/tools/libwg-go/Makefile b/tunnel/tools/libwg-go/Makefile
index 10c695e4..6c47c2d7 100644
--- a/tunnel/tools/libwg-go/Makefile
+++ b/tunnel/tools/libwg-go/Makefile
@@ -18,6 +18,7 @@ export CGO_LDFLAGS := $(CLANG_FLAGS) $(LDFLAGS) -Wl,-soname=libwg-go.so
export GOARCH := $(NDK_GO_ARCH_MAP_$(ANDROID_ARCH_NAME))
export GOOS := android
export CGO_ENABLED := 1
+export GOPATH ?= $(HOME)/go
GO_VERSION := 1.20.2
GO_PLATFORM := $(shell uname -s | tr '[:upper:]' '[:lower:]')-$(NDK_GO_ARCH_MAP_$(shell uname -m))
@@ -26,6 +27,13 @@ GO_HASH_darwin-amd64 := c93b8ced9517d07e1cd4c362c6e2d5242cb139e29b417a328fbf19ad
GO_HASH_darwin-arm64 := 7343c87f19e79c0063532e82e1c4d6f42175a32d99f7a4d15e658e88bf97f885
GO_HASH_linux-amd64 := 4eaea32f59cde4dc635fbc42161031d13e1c780b87097f4b4234cfce671f1768
+PROTOC_VERSION := 3.20.1
+PROTOC_GEN_GO := $(GOPATH)/bin/protoc-gen-go
+PROTOC := $(GRADLE_USER_HOME)/caches/protoc-$(PROTOC_VERSION)/protoc
+PROTODIR = $(CURDIR)/../../src/main/proto
+PROTO_INCLUDEDIR = $(CURDIR)/../../build/extracted-include-protos/debug
+PBDIR = $(GOPATH)/pkg/mod
+
default: $(DESTDIR)/libwg-go.so
$(GRADLE_USER_HOME)/caches/golang/$(GO_TARBALL):
@@ -44,8 +52,25 @@ $(BUILDDIR)/go-$(GO_VERSION)/.prepared: $(GRADLE_USER_HOME)/caches/golang/$(GO_T
patch -p1 -f -N -r- -d "$(dir $@)" < goruntime-boottime-over-monotonic.diff && \
touch "$@"'
+$(PROTOC_GEN_GO): export GOARCH :=
+$(PROTOC_GEN_GO): export GOOS :=
+$(PROTOC_GEN_GO): export PATH := $(BUILDDIR)/go-$(GO_VERSION)/bin/:$(PATH)
+$(PROTOC_GEN_GO): $(BUILDDIR)/go-$(GO_VERSION)/.prepared Makefile
+ go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.28
+ go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@v1.2
+
+gen/%.pb.go: export PATH := $(GOPATH)/bin:$(PATH)
+gen/%.pb.go: $(PROTODIR)/%.proto $(BUILDDIR)/go-$(GO_VERSION)/.prepared $(PROTOC_GEN_GO)
+ test -d gen || mkdir gen
+ $(PROTOC) -I $(PROTODIR) -I $(PROTO_INCLUDEDIR) --go_out=paths=source_relative:./gen $<
+
+gen/%_grpc.pb.go: export PATH := $(GOPATH)/bin:$(PATH)
+gen/%_grpc.pb.go: $(PROTODIR)/%.proto $(BUILDDIR)/go-$(GO_VERSION)/.prepared $(PROTOC_GEN_GO)
+ test -d gen || mkdir gen
+ $(PROTOC) -I $(PROTODIR) -I $(PROTO_INCLUDEDIR) --go-grpc_out=./gen --go-grpc_opt=paths=source_relative $<
+
$(DESTDIR)/libwg-go.so: export PATH := $(BUILDDIR)/go-$(GO_VERSION)/bin/:$(PATH)
-$(DESTDIR)/libwg-go.so: $(BUILDDIR)/go-$(GO_VERSION)/.prepared go.mod
+$(DESTDIR)/libwg-go.so: $(BUILDDIR)/go-$(GO_VERSION)/.prepared go.mod api-android.go service.go gen/libwg.pb.go gen/libwg_grpc.pb.go jni.c
go build -tags linux -ldflags="-X golang.zx2c4.com/wireguard/ipc.socketDirectory=/data/data/$(ANDROID_PACKAGE_NAME)/cache/wireguard" -v -trimpath -o "$@" -buildmode c-shared
.DELETE_ON_ERROR:
diff --git a/tunnel/tools/libwg-go/api-android.go b/tunnel/tools/libwg-go/api-android.go
index d47c5d76..fd0142e1 100644
--- a/tunnel/tools/libwg-go/api-android.go
+++ b/tunnel/tools/libwg-go/api-android.go
@@ -48,6 +48,7 @@ func (l AndroidLogger) Printf(format string, args ...interface{}) {
type TunnelHandle struct {
device *device.Device
uapi net.Listener
+ logger *device.Logger
}
var tunnelHandles map[int32]TunnelHandle
@@ -208,20 +209,40 @@ func wgGetConfig(tunnelHandle int32) *C.char {
//export wgVersion
func wgVersion() *C.char {
+ return C.CString(Version())
+}
+
+func Version() string {
info, ok := debug.ReadBuildInfo()
if !ok {
- return C.CString("unknown")
+ return "unknown"
}
for _, dep := range info.Deps {
if dep.Path == "golang.zx2c4.com/wireguard" {
parts := strings.Split(dep.Version, "-")
if len(parts) == 3 && len(parts[2]) == 12 {
- return C.CString(parts[2][:7])
+ return parts[2][:7]
}
- return C.CString(dep.Version)
+ return dep.Version
}
}
- return C.CString("unknown")
+ return "unknown"
+}
+
+//export wgStartGrpc
+func wgStartGrpc(sock_path string) C.int{
+ tag := cstring("WireGuard/GoBackend/gRPC")
+ logger := &device.Logger{
+ Verbosef: AndroidLogger{level: C.ANDROID_LOG_DEBUG, tag: tag}.Printf,
+ Errorf: AndroidLogger{level: C.ANDROID_LOG_ERROR, tag: tag}.Printf,
+ }
+
+ res, errmsg := StartGrpc(sock_path, logger)
+ if res < 0 {
+ logger.Verbosef("wgStartGrpc: %v (%v)", errmsg, res)
+ }
+
+ return C.int(res)
}
func main() {}
diff --git a/tunnel/tools/libwg-go/jni.c b/tunnel/tools/libwg-go/jni.c
index 7ad94d35..121729a7 100644
--- a/tunnel/tools/libwg-go/jni.c
+++ b/tunnel/tools/libwg-go/jni.c
@@ -14,6 +14,7 @@ extern int wgGetSocketV4(int handle);
extern int wgGetSocketV6(int handle);
extern char *wgGetConfig(int handle);
extern char *wgVersion();
+extern int wgStartGrpc();
JNIEXPORT jint JNICALL Java_com_wireguard_android_backend_GoBackend_wgTurnOn(JNIEnv *env, jclass c, jstring ifname, jint tun_fd, jstring settings)
{
@@ -69,3 +70,15 @@ JNIEXPORT jstring JNICALL Java_com_wireguard_android_backend_GoBackend_wgVersion
free(version);
return ret;
}
+
+JNIEXPORT jint JNICALL Java_com_wireguard_android_backend_GoBackend_wgStartGrpc(JNIEnv *env, jclass c, jstring sockname)
+{
+ const char *sockname_str = (*env)->GetStringUTFChars(env, sockname, 0);
+ size_t sockname_len = (*env)->GetStringUTFLength(env, sockname);
+ jint res = wgStartGrpc((struct go_string){
+ .str = sockname_str,
+ .n = sockname_len
+ });
+ (*env)->ReleaseStringUTFChars(env, sockname, sockname_str);
+ return res;
+}
diff --git a/tunnel/tools/libwg-go/service.go b/tunnel/tools/libwg-go/service.go
new file mode 100644
index 00000000..2a0dfb2d
--- /dev/null
+++ b/tunnel/tools/libwg-go/service.go
@@ -0,0 +1,76 @@
+package main
+
+import (
+ "context"
+ "fmt"
+ "net"
+ "os"
+
+ "google.golang.org/grpc"
+
+ gen "golang.zx2c4.com/wireguard/android/gen"
+ "golang.zx2c4.com/wireguard/device"
+)
+
+type LibwgServiceImpl struct {
+ gen.UnimplementedLibwgServer
+ logger *device.Logger
+}
+
+var _ gen.LibwgServer = (*LibwgServiceImpl)(nil)
+var server *grpc.Server
+
+func NewLibwgService(logger *device.Logger) gen.LibwgServer {
+ return &LibwgServiceImpl{logger: logger}
+}
+
+func StartGrpc(sock_path string, logger *device.Logger) (int, string) {
+ if server != nil {
+ return -1, "Already started"
+ }
+
+ if _, err := os.Stat(sock_path); err == nil {
+ if err := os.RemoveAll(sock_path); err != nil {
+ return -1, fmt.Sprintf("Cleanup failed: %v %v", sock_path, err)
+ }
+ }
+
+ listener, err := net.Listen("unix", sock_path)
+ if err != nil {
+ return -1, fmt.Sprintf("Listen failed: %v %v", sock_path, err)
+ }
+
+ server = grpc.NewServer()
+ service := NewLibwgService(logger)
+
+ gen.RegisterLibwgServer(server, service)
+
+ go func() {
+ server.Serve(listener)
+ }()
+
+ logger.Verbosef("gRPC started")
+
+ return 0, ""
+}
+
+func (e *LibwgServiceImpl) Version(ctx context.Context, req *gen.VersionRequest) (*gen.VersionResponse, error) {
+
+ r := &gen.VersionResponse{
+ Version: Version(),
+ }
+
+ return r, nil
+}
+
+func (e *LibwgServiceImpl) StopGrpc(ctx context.Context, req *gen.StopGrpcRequest) (*gen.StopGrpcResponse, error) {
+ if server != nil {
+ server.Stop()
+ server = nil
+ }
+
+ r := &gen.StopGrpcResponse{
+ }
+
+ return r, nil
+}