android fix - libwg-go added

This commit is contained in:
pokamest 2021-09-30 21:09:48 +03:00
parent 969fc899a0
commit 476aabe671
8 changed files with 619 additions and 0 deletions

View file

@ -0,0 +1,44 @@
# SPDX-License-Identifier: Apache-2.0
#
# Copyright © 2018-2019 WireGuard LLC. All Rights Reserved.
cmake_minimum_required(VERSION 3.4.1)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}")
message("PROJECT_SOURCE_DIR ${PROJECT_SOURCE_DIR}")
set( CMAKE_WG_TOOLS_DIR ../../../desktop-client/client/3rd/wireguard-tools )
find_program(CCACHE_FOUND ccache)
if(CCACHE_FOUND)
set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ccache)
set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK ccache)
endif(CCACHE_FOUND)
# Work around https://github.com/android-ndk/ndk/issues/602
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fuse-ld=gold")
add_executable(libwg-quick.so ${CMAKE_WG_TOOLS_DIR}/src/wg-quick/android.c ndk-compat/compat.c)
target_compile_options(libwg-quick.so PUBLIC -O3 -std=gnu11 -Wall -include ${CMAKE_CURRENT_SOURCE_DIR}/ndk-compat/compat.h -DWG_PACKAGE_NAME=\"${ANDROID_PACKAGE_NAME}\")
target_link_libraries(libwg-quick.so -ldl)
file(GLOB WG_SOURCES ${CMAKE_WG_TOOLS_DIR}/src/*.c ndk-compat/compat.c)
add_executable(libwg.so ${WG_SOURCES})
target_include_directories(libwg.so PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/${CMAKE_WG_TOOLS_DIR}/src/uapi/linux/" "${CMAKE_CURRENT_SOURCE_DIR}/${CMAKE_WG_TOOLS_DIR}/src/")
target_compile_options(libwg.so PUBLIC -O3 -std=gnu11 -D_GNU_SOURCE -include ${CMAKE_CURRENT_SOURCE_DIR}/ndk-compat/compat.h -DHAVE_VISIBILITY_HIDDEN -DRUNSTATEDIR=\"/data/data/${ANDROID_PACKAGE_NAME}/cache\")
add_custom_target(libwg-go.so WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/libwg-go" COMMENT "Building wireguard-go"
ANDROID_ARCH_NAME=${ANDROID_ARCH_NAME}
ANDROID_C_COMPILER=${ANDROID_C_COMPILER}
ANDROID_TOOLCHAIN_ROOT=${ANDROID_TOOLCHAIN_ROOT}
ANDROID_LLVM_TRIPLE=${ANDROID_LLVM_TRIPLE}
ANDROID_SYSROOT=${ANDROID_SYSROOT}
ANDROID_PACKAGE_NAME=${ANDROID_PACKAGE_NAME}
GRADLE_USER_HOME=${GRADLE_USER_HOME}
CFLAGS=${CMAKE_C_FLAGS}\ -Wno-unused-command-line-argument
LDFLAGS=${CMAKE_SHARED_LINKER_FLAGS}\ -fuse-ld=gold
DESTDIR=${CMAKE_LIBRARY_OUTPUT_DIRECTORY}
BUILDDIR=${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/../generated-src
)
# Hack to make it actually build as part of the default target
add_dependencies(libwg.so libwg-go.so)

View file

@ -0,0 +1,227 @@
/* SPDX-License-Identifier: Apache-2.0
*
* Copyright (C) 2017-2019 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
*/
package main
// #cgo LDFLAGS: -llog
// #include <android/log.h>
import "C"
import (
"fmt"
"math"
"net"
"os"
"os/signal"
"runtime"
"runtime/debug"
"strings"
"unsafe"
"golang.org/x/sys/unix"
"golang.zx2c4.com/wireguard/conn"
"golang.zx2c4.com/wireguard/device"
"golang.zx2c4.com/wireguard/ipc"
"golang.zx2c4.com/wireguard/tun"
)
type AndroidLogger struct {
level C.int
tag *C.char
}
func cstring(s string) *C.char {
b, err := unix.BytePtrFromString(s)
if err != nil {
b := [1]C.char{}
return &b[0]
}
return (*C.char)(unsafe.Pointer(b))
}
func (l AndroidLogger) Printf(format string, args ...interface{}) {
C.__android_log_write(l.level, l.tag, cstring(fmt.Sprintf(format, args...)))
}
type TunnelHandle struct {
device *device.Device
uapi net.Listener
}
var tunnelHandles map[int32]TunnelHandle
func init() {
tunnelHandles = make(map[int32]TunnelHandle)
signals := make(chan os.Signal)
signal.Notify(signals, unix.SIGUSR2)
go func() {
buf := make([]byte, os.Getpagesize())
for {
select {
case <-signals:
n := runtime.Stack(buf, true)
if n == len(buf) {
n--
}
buf[n] = 0
C.__android_log_write(C.ANDROID_LOG_ERROR, cstring("WireGuard/GoBackend/Stacktrace"), (*C.char)(unsafe.Pointer(&buf[0])))
}
}
}()
}
//export wgTurnOn
func wgTurnOn(interfaceName string, tunFd int32, settings string) int32 {
tag := cstring("WireGuard/GoBackend/" + interfaceName)
logger := &device.Logger{
Verbosef: AndroidLogger{level: C.ANDROID_LOG_DEBUG, tag: tag}.Printf,
Errorf: AndroidLogger{level: C.ANDROID_LOG_ERROR, tag: tag}.Printf,
}
tun, name, err := tun.CreateUnmonitoredTUNFromFD(int(tunFd))
if err != nil {
unix.Close(int(tunFd))
logger.Errorf("CreateUnmonitoredTUNFromFD: %v", err)
return -1
}
logger.Verbosef("Attaching to interface %v", name)
device := device.NewDevice(tun, conn.NewStdNetBind(), logger)
err = device.IpcSet(settings)
if err != nil {
unix.Close(int(tunFd))
logger.Errorf("IpcSet: %v", err)
return -1
}
device.DisableSomeRoamingForBrokenMobileSemantics()
var uapi net.Listener
uapiFile, err := ipc.UAPIOpen(name)
if err != nil {
logger.Errorf("UAPIOpen: %v", err)
} else {
uapi, err = ipc.UAPIListen(name, uapiFile)
if err != nil {
uapiFile.Close()
logger.Errorf("UAPIListen: %v", err)
} else {
go func() {
for {
conn, err := uapi.Accept()
if err != nil {
return
}
go device.IpcHandle(conn)
}
}()
}
}
err = device.Up()
if err != nil {
logger.Errorf("Unable to bring up device: %v", err)
uapiFile.Close()
device.Close()
return -1
}
logger.Verbosef("Device started")
var i int32
for i = 0; i < math.MaxInt32; i++ {
if _, exists := tunnelHandles[i]; !exists {
break
}
}
if i == math.MaxInt32 {
logger.Errorf("Unable to find empty handle")
uapiFile.Close()
device.Close()
return -1
}
tunnelHandles[i] = TunnelHandle{device: device, uapi: uapi}
return i
}
//export wgTurnOff
func wgTurnOff(tunnelHandle int32) {
handle, ok := tunnelHandles[tunnelHandle]
if !ok {
return
}
delete(tunnelHandles, tunnelHandle)
if handle.uapi != nil {
handle.uapi.Close()
}
handle.device.Close()
}
//export wgGetSocketV4
func wgGetSocketV4(tunnelHandle int32) int32 {
handle, ok := tunnelHandles[tunnelHandle]
if !ok {
return -1
}
bind, _ := handle.device.Bind().(conn.PeekLookAtSocketFd)
if bind == nil {
return -1
}
fd, err := bind.PeekLookAtSocketFd4()
if err != nil {
return -1
}
return int32(fd)
}
//export wgGetSocketV6
func wgGetSocketV6(tunnelHandle int32) int32 {
handle, ok := tunnelHandles[tunnelHandle]
if !ok {
return -1
}
bind, _ := handle.device.Bind().(conn.PeekLookAtSocketFd)
if bind == nil {
return -1
}
fd, err := bind.PeekLookAtSocketFd6()
if err != nil {
return -1
}
return int32(fd)
}
//export wgGetConfig
func wgGetConfig(tunnelHandle int32) *C.char {
handle, ok := tunnelHandles[tunnelHandle]
if !ok {
return nil
}
settings, err := handle.device.IpcGet()
if err != nil {
return nil
}
return C.CString(settings)
}
//export wgVersion
func wgVersion() *C.char {
info, ok := debug.ReadBuildInfo()
if !ok {
return C.CString("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 C.CString(dep.Version)
}
}
return C.CString("unknown")
}
func main() {}

View file

@ -0,0 +1,10 @@
module golang.zx2c4.com/wireguard/android
go 1.16
require (
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83 // indirect
golang.org/x/net v0.0.0-20210220033124-5f55cee0dc0d // indirect
golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43
golang.zx2c4.com/wireguard v0.0.0-20210222142647-219296a1e787
)

View file

@ -0,0 +1,21 @@
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83 h1:/ZScEX8SfEmUGRHs0gxpqteO5nfNW6axyZbBdw9A12g=
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210220033124-5f55cee0dc0d h1:1aflnvSoWWLI2k/dMUAl5lvU1YO4Mb4hz0gh+1rjcxU=
golang.org/x/net v0.0.0-20210220033124-5f55cee0dc0d/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210105210732-16f7687f5001/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43 h1:SgQ6LNaYJU0JIuEHv9+s6EbhSCwYeAf5Yvj6lpYlqAE=
golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.zx2c4.com/wireguard v0.0.0-20210222142647-219296a1e787 h1:zrctiUlt4hD1sgxBYrG5CAjobVhpdxnUXy+qyWWLR1w=
golang.zx2c4.com/wireguard v0.0.0-20210222142647-219296a1e787/go.mod h1:LofpIKqPJNvHiwKXuzsBshJCTe7IgRAz3iizquljFDk=

View file

@ -0,0 +1,161 @@
From b83553d9f260ba20c6faaa52e6fe6f74309eb41a Mon Sep 17 00:00:00 2001
From: "Jason A. Donenfeld" <Jason@zx2c4.com>
Date: Mon, 22 Feb 2021 02:36:03 +0100
Subject: [PATCH] runtime: use CLOCK_BOOTTIME in nanotime on Linux
This makes timers account for having expired while a computer was
asleep, which is quite common on mobile devices. Note that BOOTTIME is
identical to MONOTONIC, except that it takes into account time spent
in suspend. In Linux 4.17, the kernel will actually make MONOTONIC act
like BOOTTIME anyway, so this switch will additionally unify the
timer behavior across kernels.
BOOTTIME was introduced into Linux 2.6.39-rc1 with 70a08cca1227d in
2011.
Fixes #24595
Change-Id: I7b2a6ca0c5bc5fce57ec0eeafe7b68270b429321
---
src/runtime/sys_linux_386.s | 4 ++--
src/runtime/sys_linux_amd64.s | 2 +-
src/runtime/sys_linux_arm.s | 4 ++--
src/runtime/sys_linux_arm64.s | 4 ++--
src/runtime/sys_linux_mips64x.s | 2 +-
src/runtime/sys_linux_mipsx.s | 2 +-
src/runtime/sys_linux_ppc64x.s | 2 +-
src/runtime/sys_linux_s390x.s | 2 +-
8 files changed, 11 insertions(+), 11 deletions(-)
diff --git a/src/runtime/sys_linux_386.s b/src/runtime/sys_linux_386.s
index 1e3a834812..78b6021fc7 100644
--- a/src/runtime/sys_linux_386.s
+++ b/src/runtime/sys_linux_386.s
@@ -337,13 +337,13 @@ noswitch:
LEAL 8(SP), BX // &ts (struct timespec)
MOVL BX, 4(SP)
- MOVL $1, 0(SP) // CLOCK_MONOTONIC
+ MOVL $7, 0(SP) // CLOCK_BOOTTIME
CALL AX
JMP finish
fallback:
MOVL $SYS_clock_gettime, AX
- MOVL $1, BX // CLOCK_MONOTONIC
+ MOVL $7, BX // CLOCK_BOOTTIME
LEAL 8(SP), CX
INVOKE_SYSCALL
diff --git a/src/runtime/sys_linux_amd64.s b/src/runtime/sys_linux_amd64.s
index 37cb8dad03..e8b730bcaa 100644
--- a/src/runtime/sys_linux_amd64.s
+++ b/src/runtime/sys_linux_amd64.s
@@ -302,7 +302,7 @@ noswitch:
SUBQ $16, SP // Space for results
ANDQ $~15, SP // Align for C code
- MOVL $1, DI // CLOCK_MONOTONIC
+ MOVL $7, DI // CLOCK_BOOTTIME
LEAQ 0(SP), SI
MOVQ runtime·vdsoClockgettimeSym(SB), AX
CMPQ AX, $0
diff --git a/src/runtime/sys_linux_arm.s b/src/runtime/sys_linux_arm.s
index 475f52344c..bb567abcf4 100644
--- a/src/runtime/sys_linux_arm.s
+++ b/src/runtime/sys_linux_arm.s
@@ -11,7 +11,7 @@
#include "textflag.h"
#define CLOCK_REALTIME 0
-#define CLOCK_MONOTONIC 1
+#define CLOCK_BOOTTIME 7
// for EABI, as we don't support OABI
#define SYS_BASE 0x0
@@ -366,7 +366,7 @@ noswitch:
SUB $24, R13 // Space for results
BIC $0x7, R13 // Align for C code
- MOVW $CLOCK_MONOTONIC, R0
+ MOVW $CLOCK_BOOTTIME, R0
MOVW $8(R13), R1 // timespec
MOVW runtime·vdsoClockgettimeSym(SB), R2
CMP $0, R2
diff --git a/src/runtime/sys_linux_arm64.s b/src/runtime/sys_linux_arm64.s
index 198a5bacef..9715387f36 100644
--- a/src/runtime/sys_linux_arm64.s
+++ b/src/runtime/sys_linux_arm64.s
@@ -13,7 +13,7 @@
#define AT_FDCWD -100
#define CLOCK_REALTIME 0
-#define CLOCK_MONOTONIC 1
+#define CLOCK_BOOTTIME 7
#define SYS_exit 93
#define SYS_read 63
@@ -319,7 +319,7 @@ noswitch:
BIC $15, R1
MOVD R1, RSP
- MOVW $CLOCK_MONOTONIC, R0
+ MOVW $CLOCK_BOOTTIME, R0
MOVD runtime·vdsoClockgettimeSym(SB), R2
CBZ R2, fallback
diff --git a/src/runtime/sys_linux_mips64x.s b/src/runtime/sys_linux_mips64x.s
index c3e9f37694..e3879acd38 100644
--- a/src/runtime/sys_linux_mips64x.s
+++ b/src/runtime/sys_linux_mips64x.s
@@ -312,7 +312,7 @@ noswitch:
AND $~15, R1 // Align for C code
MOVV R1, R29
- MOVW $1, R4 // CLOCK_MONOTONIC
+ MOVW $7, R4 // CLOCK_BOOTTIME
MOVV $0(R29), R5
MOVV runtime·vdsoClockgettimeSym(SB), R25
diff --git a/src/runtime/sys_linux_mipsx.s b/src/runtime/sys_linux_mipsx.s
index fab2ab3892..f9af103594 100644
--- a/src/runtime/sys_linux_mipsx.s
+++ b/src/runtime/sys_linux_mipsx.s
@@ -238,7 +238,7 @@ TEXT runtime·walltime1(SB),NOSPLIT,$8-12
RET
TEXT runtime·nanotime1(SB),NOSPLIT,$8-8
- MOVW $1, R4 // CLOCK_MONOTONIC
+ MOVW $7, R4 // CLOCK_BOOTTIME
MOVW $4(R29), R5
MOVW $SYS_clock_gettime, R2
SYSCALL
diff --git a/src/runtime/sys_linux_ppc64x.s b/src/runtime/sys_linux_ppc64x.s
index fd69ee70a5..ff6bc8355b 100644
--- a/src/runtime/sys_linux_ppc64x.s
+++ b/src/runtime/sys_linux_ppc64x.s
@@ -249,7 +249,7 @@ fallback:
JMP finish
TEXT runtime·nanotime1(SB),NOSPLIT,$16-8
- MOVD $1, R3 // CLOCK_MONOTONIC
+ MOVD $7, R3 // CLOCK_BOOTTIME
MOVD R1, R15 // R15 is unchanged by C code
MOVD g_m(g), R21 // R21 = m
diff --git a/src/runtime/sys_linux_s390x.s b/src/runtime/sys_linux_s390x.s
index c15a1d5364..f52c4d5098 100644
--- a/src/runtime/sys_linux_s390x.s
+++ b/src/runtime/sys_linux_s390x.s
@@ -207,7 +207,7 @@ TEXT runtime·walltime1(SB),NOSPLIT,$16
RET
TEXT runtime·nanotime1(SB),NOSPLIT,$16
- MOVW $1, R2 // CLOCK_MONOTONIC
+ MOVW $7, R2 // CLOCK_BOOTTIME
MOVD $tp-16(SP), R3
MOVW $SYS_clock_gettime, R1
SYSCALL
--
2.30.1

View file

@ -0,0 +1,70 @@
/* SPDX-License-Identifier: Apache-2.0
*
* Copyright © 2017-2019 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights
* Reserved.
*/
#include <jni.h>
#include <stdlib.h>
#include <string.h>
struct go_string {
const char* str;
long n;
};
extern int wgTurnOn(struct go_string ifname, int tun_fd,
struct go_string settings);
extern void wgTurnOff(int handle);
extern int wgGetSocketV4(int handle);
extern int wgGetSocketV6(int handle);
extern char* wgGetConfig(int handle);
extern char* wgVersion();
JNIEXPORT jint JNICALL Java_org_mozilla_firefox_vpn_VPNService_wgTurnOn(
JNIEnv* env, jclass c, jstring ifname, jint tun_fd, jstring settings) {
const char* ifname_str = (*env)->GetStringUTFChars(env, ifname, 0);
size_t ifname_len = (*env)->GetStringUTFLength(env, ifname);
const char* settings_str = (*env)->GetStringUTFChars(env, settings, 0);
size_t settings_len = (*env)->GetStringUTFLength(env, settings);
int ret =
wgTurnOn((struct go_string){.str = ifname_str, .n = ifname_len}, tun_fd,
(struct go_string){.str = settings_str, .n = settings_len});
(*env)->ReleaseStringUTFChars(env, ifname, ifname_str);
(*env)->ReleaseStringUTFChars(env, settings, settings_str);
return ret;
}
JNIEXPORT void JNICALL Java_org_mozilla_firefox_vpn_VPNService_wgTurnOff(
JNIEnv* env, jclass c, jint handle) {
wgTurnOff(handle);
}
JNIEXPORT jint JNICALL Java_org_mozilla_firefox_vpn_VPNService_wgGetSocketV4(
JNIEnv* env, jclass c, jint handle) {
return wgGetSocketV4(handle);
}
JNIEXPORT jint JNICALL Java_org_mozilla_firefox_vpn_VPNService_wgGetSocketV6(
JNIEnv* env, jclass c, jint handle) {
return wgGetSocketV6(handle);
}
JNIEXPORT jstring JNICALL Java_org_mozilla_firefox_vpn_VPNService_wgGetConfig(
JNIEnv* env, jclass c, jint handle) {
jstring ret;
char* config = wgGetConfig(handle);
if (!config) return NULL;
ret = (*env)->NewStringUTF(env, config);
free(config);
return ret;
}
JNIEXPORT jstring JNICALL
Java_org_mozilla_firefox_vpn_VPNService_wgVersion(JNIEnv* env, jclass c) {
jstring ret;
char* version = wgVersion();
if (!version) return NULL;
ret = (*env)->NewStringUTF(env, version);
free(version);
return ret;
}

View file

@ -0,0 +1,71 @@
/* SPDX-License-Identifier: BSD
*
* Copyright © 2017-2019 WireGuard LLC. All Rights Reserved.
*
*/
#define FILE_IS_EMPTY
#if defined(__ANDROID_API__) && __ANDROID_API__ < 18
# undef FILE_IS_EMPTY
# include <stdio.h>
# include <stdlib.h>
ssize_t getdelim(char** buf, size_t* bufsiz, int delimiter, FILE* fp) {
char *ptr, *eptr;
if (*buf == NULL || *bufsiz == 0) {
*bufsiz = BUFSIZ;
if ((*buf = malloc(*bufsiz)) == NULL) return -1;
}
for (ptr = *buf, eptr = *buf + *bufsiz;;) {
int c = fgetc(fp);
if (c == -1) {
if (feof(fp)) {
ssize_t diff = (ssize_t)(ptr - *buf);
if (diff != 0) {
*ptr = '\0';
return diff;
}
}
return -1;
}
*ptr++ = c;
if (c == delimiter) {
*ptr = '\0';
return ptr - *buf;
}
if (ptr + 2 >= eptr) {
char* nbuf;
size_t nbufsiz = *bufsiz * 2;
ssize_t d = ptr - *buf;
if ((nbuf = realloc(*buf, nbufsiz)) == NULL) return -1;
*buf = nbuf;
*bufsiz = nbufsiz;
eptr = nbuf + nbufsiz;
ptr = nbuf + d;
}
}
}
ssize_t getline(char** buf, size_t* bufsiz, FILE* fp) {
return getdelim(buf, bufsiz, '\n', fp);
}
#endif
#if defined(__ANDROID_API__) && __ANDROID_API__ < 24
# undef FILE_IS_EMPTY
# include <string.h>
char* strchrnul(const char* s, int c) {
char* x = strchr(s, c);
if (!x) return (char*)s + strlen(s);
return x;
}
#endif
#ifdef FILE_IS_EMPTY
# undef FILE_IS_EMPTY
static char ____x __attribute__((unused));
#endif

View file

@ -0,0 +1,15 @@
/* SPDX-License-Identifier: BSD
*
* Copyright © 2017-2019 WireGuard LLC. All Rights Reserved.
*
*/
#if defined(__ANDROID_API__) && __ANDROID_API__ < 18
# include <stdio.h>
ssize_t getdelim(char** buf, size_t* bufsiz, int delimiter, FILE* fp);
ssize_t getline(char** buf, size_t* bufsiz, FILE* fp);
#endif
#if defined(__ANDROID_API__) && __ANDROID_API__ < 24
char* strchrnul(const char* s, int c);
#endif