diff options
-rw-r--r-- | build.gradle | 3 | ||||
-rw-r--r-- | tunnel/build.gradle | 53 | ||||
-rw-r--r-- | tunnel/src/main/java/com/wireguard/android/backend/GoBackend.java | 32 | ||||
-rw-r--r-- | tunnel/src/main/java/com/wireguard/android/backend/LocalSocketAdapter.java | 325 | ||||
-rw-r--r-- | tunnel/src/main/java/com/wireguard/android/backend/UnixDomainSocketFactory.java | 59 | ||||
-rw-r--r-- | tunnel/src/main/proto/libwg.proto | 27 | ||||
-rw-r--r-- | tunnel/tools/libwg-go/.gitignore | 3 | ||||
-rw-r--r-- | tunnel/tools/libwg-go/Makefile | 27 | ||||
-rw-r--r-- | tunnel/tools/libwg-go/api-android.go | 29 | ||||
-rw-r--r-- | tunnel/tools/libwg-go/jni.c | 13 | ||||
-rw-r--r-- | tunnel/tools/libwg-go/service.go | 76 |
11 files changed, 640 insertions, 7 deletions
diff --git a/build.gradle b/build.gradle index 9c6c42a1..2c827e2a 100644 --- a/build.gradle +++ b/build.gradle @@ -12,11 +12,14 @@ buildscript { datastoreVersion = '1.0.0' desugarVersion = '1.1.5' fragmentVersion = '1.5.5' + grpcVersion = '1.46.0' jsr305Version = '3.0.2' junitVersion = '4.13.2' lifecycleRuntimeKtxVersion = '2.6.0' materialComponentsVersion = '1.8.0' preferenceVersion = '1.2.0' + protobufGradleVersion = '0.8.18' + protocVersion = '3.20.1' zxingEmbeddedVersion = '4.3.0' groupName = 'com.wireguard.android' diff --git a/tunnel/build.gradle b/tunnel/build.gradle index 9a5c6d63..9db1bf13 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 @@ -57,8 +64,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 +} |