Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
AndroidUtils
VPNTunnelProxy
Commits
282f4783
Commit
282f4783
authored
Aug 19, 2021
by
Daniel Wolf
Browse files
Merge remote-tracking branch 'origin/master'
parents
6255f0b9
d76c046d
Changes
14
Hide whitespace changes
Inline
Side-by-side
.gitignore
View file @
282f4783
...
...
@@ -151,3 +151,7 @@ libs/
.idea/**/dbnavigator.xml
.idea/**/markdown-navigator-enh.xml
.idea/**/markdown-navigator.xml
.idea/jarRepositories.xml
.idea/runConfigurations.xml
.idea/misc.xml
.idea/.name
\ No newline at end of file
.gitlab-ci.yml
View file @
282f4783
...
...
@@ -3,21 +3,8 @@ image: thyrlian/android-sdk
before_script
:
-
chmod +x gradlew
test
:
test
-build-deploy
:
stage
:
test
script
:
-
./gradlew clean assembleRelease test --stacktrace || (find . -type d -wholename "**reports/tests" -exec zip -ru tests.zip {} \; && exit 1)
-
find . -type d -wholename "**reports/tests" -exec zip -ru tests.zip {} \;
except
:
-
/^no_ci.*$/
-
/^no_tests.*$/
artifacts
:
when
:
always
paths
:
-
tests.zip
deploy
:
stage
:
deploy
script
:
-
./gradlew clean assembleRelease sourcesJar javadocJar
-
./gradlew publish --stacktrace
\ No newline at end of file
-
./gradlew clean assembleRelease sourcesJar test --stacktrace
-
./gradlew publish --stacktrace
\ No newline at end of file
.idea/compiler.xml
0 → 100644
View file @
282f4783
<?xml version="1.0" encoding="UTF-8"?>
<project
version=
"4"
>
<component
name=
"CompilerConfiguration"
>
<bytecodeTargetLevel
target=
"14"
/>
</component>
</project>
\ No newline at end of file
.idea/misc.xml
deleted
100644 → 0
View file @
6255f0b9
<?xml version="1.0" encoding="UTF-8"?>
<project
version=
"4"
>
<component
name=
"NullableNotNullManager"
>
<option
name=
"myDefaultNullable"
value=
"android.support.annotation.Nullable"
/>
<option
name=
"myDefaultNotNull"
value=
"android.support.annotation.NonNull"
/>
<option
name=
"myNullables"
>
<value>
<list
size=
"12"
>
<item
index=
"0"
class=
"java.lang.String"
itemvalue=
"org.jetbrains.annotations.Nullable"
/>
<item
index=
"1"
class=
"java.lang.String"
itemvalue=
"javax.annotation.Nullable"
/>
<item
index=
"2"
class=
"java.lang.String"
itemvalue=
"javax.annotation.CheckForNull"
/>
<item
index=
"3"
class=
"java.lang.String"
itemvalue=
"edu.umd.cs.findbugs.annotations.Nullable"
/>
<item
index=
"4"
class=
"java.lang.String"
itemvalue=
"android.support.annotation.Nullable"
/>
<item
index=
"5"
class=
"java.lang.String"
itemvalue=
"androidx.annotation.Nullable"
/>
<item
index=
"6"
class=
"java.lang.String"
itemvalue=
"androidx.annotation.RecentlyNullable"
/>
<item
index=
"7"
class=
"java.lang.String"
itemvalue=
"org.checkerframework.checker.nullness.qual.Nullable"
/>
<item
index=
"8"
class=
"java.lang.String"
itemvalue=
"org.checkerframework.checker.nullness.compatqual.NullableDecl"
/>
<item
index=
"9"
class=
"java.lang.String"
itemvalue=
"org.checkerframework.checker.nullness.compatqual.NullableType"
/>
<item
index=
"10"
class=
"java.lang.String"
itemvalue=
"android.annotation.Nullable"
/>
<item
index=
"11"
class=
"java.lang.String"
itemvalue=
"com.android.annotations.Nullable"
/>
</list>
</value>
</option>
<option
name=
"myNotNulls"
>
<value>
<list
size=
"11"
>
<item
index=
"0"
class=
"java.lang.String"
itemvalue=
"org.jetbrains.annotations.NotNull"
/>
<item
index=
"1"
class=
"java.lang.String"
itemvalue=
"javax.annotation.Nonnull"
/>
<item
index=
"2"
class=
"java.lang.String"
itemvalue=
"edu.umd.cs.findbugs.annotations.NonNull"
/>
<item
index=
"3"
class=
"java.lang.String"
itemvalue=
"android.support.annotation.NonNull"
/>
<item
index=
"4"
class=
"java.lang.String"
itemvalue=
"androidx.annotation.NonNull"
/>
<item
index=
"5"
class=
"java.lang.String"
itemvalue=
"androidx.annotation.RecentlyNonNull"
/>
<item
index=
"6"
class=
"java.lang.String"
itemvalue=
"org.checkerframework.checker.nullness.qual.NonNull"
/>
<item
index=
"7"
class=
"java.lang.String"
itemvalue=
"org.checkerframework.checker.nullness.compatqual.NonNullDecl"
/>
<item
index=
"8"
class=
"java.lang.String"
itemvalue=
"org.checkerframework.checker.nullness.compatqual.NonNullType"
/>
<item
index=
"9"
class=
"java.lang.String"
itemvalue=
"android.annotation.NonNull"
/>
<item
index=
"10"
class=
"java.lang.String"
itemvalue=
"com.android.annotations.NonNull"
/>
</list>
</value>
</option>
</component>
<component
name=
"ProjectRootManager"
version=
"2"
languageLevel=
"JDK_1_8"
project-jdk-name=
"JDK"
project-jdk-type=
"JavaSDK"
>
<output
url=
"file://$PROJECT_DIR$/build/classes"
/>
</component>
<component
name=
"ProjectType"
>
<option
name=
"id"
value=
"Android"
/>
</component>
</project>
\ No newline at end of file
.idea/runConfigurations.xml
deleted
100644 → 0
View file @
6255f0b9
<?xml version="1.0" encoding="UTF-8"?>
<project
version=
"4"
>
<component
name=
"RunConfigurationProducerService"
>
<option
name=
"ignoredProducers"
>
<set>
<option
value=
"org.jetbrains.plugins.gradle.execution.test.runner.AllInPackageGradleConfigurationProducer"
/>
<option
value=
"org.jetbrains.plugins.gradle.execution.test.runner.TestClassGradleConfigurationProducer"
/>
<option
value=
"org.jetbrains.plugins.gradle.execution.test.runner.TestMethodGradleConfigurationProducer"
/>
</set>
</option>
</component>
</project>
\ No newline at end of file
build.gradle
View file @
282f4783
...
...
@@ -24,14 +24,14 @@ ext.nexus_user = getNexusUser()
ext
.
nexus_password
=
getNexusPassword
()
buildscript
{
ext
.
ANDROID_COMPILE_SDK
=
(
System
.
getenv
(
"ANDROID_COMPILE_SDK"
)
==
null
?
29
:
System
.
getenv
(
"ANDROID_COMPILE_SDK"
)).
toInteger
()
ext
.
ANDROID_COMPILE_SDK
=
(
System
.
getenv
(
"ANDROID_COMPILE_SDK"
)
==
null
?
30
:
System
.
getenv
(
"ANDROID_COMPILE_SDK"
)).
toInteger
()
ext
.
ANDROID_TARGET_SDK
=
(
System
.
getenv
(
"ANDROID_TARGET_SDK"
)
==
null
?
ANDROID_COMPILE_SDK
:
System
.
getenv
(
"ANDROID_TARGET_SDK"
)).
toInteger
()
ext
.
ANDROID_MIN_SDK
=
(
System
.
getenv
(
"ANDROID_MIN_SDK"
)
==
null
?
21
:
System
.
getenv
(
"ANDROID_COMPILE_SDK"
)).
toInteger
()
ext
.
KOTLIN_VERSION
=
System
.
getenv
(
"KOTLIN_VERSION"
)
==
null
?
"1.
4.10
"
:
System
.
getenv
(
"KOTLIN_VERSION"
)
ext
.
ANDROID_GRADLE_PLUGIN_VERSION
=
System
.
getenv
(
"ANDROID_GRADLE_PLUGIN_VERSION"
)
==
null
?
"
4
.0.
1
"
:
System
.
getenv
(
"ANDROID_GRADLE_PLUGIN_VERSION"
)
ext
.
APPCOMPAT_VERSION
=
"1.
2.0
"
ext
.
COROUTINE_VERSION
=
"1.
3.9
"
ext
.
RECYCLERVIEW_VERSION
=
"1.
1
.0"
ext
.
KOTLIN_VERSION
=
System
.
getenv
(
"KOTLIN_VERSION"
)
==
null
?
"1.
5.21
"
:
System
.
getenv
(
"KOTLIN_VERSION"
)
ext
.
ANDROID_GRADLE_PLUGIN_VERSION
=
System
.
getenv
(
"ANDROID_GRADLE_PLUGIN_VERSION"
)
==
null
?
"
7
.0.
0
"
:
System
.
getenv
(
"ANDROID_GRADLE_PLUGIN_VERSION"
)
ext
.
APPCOMPAT_VERSION
=
"1.
3.1
"
ext
.
COROUTINE_VERSION
=
"1.
5.1
"
ext
.
RECYCLERVIEW_VERSION
=
"1.
2
.0"
ext
.
ROBOELECTRIC_VERSION
=
"4.3"
println
"COMPILE SDK Version: $ANDROID_COMPILE_SDK"
...
...
@@ -41,13 +41,11 @@ buildscript {
repositories
{
google
()
jcenter
()
mavenCentral
()
}
dependencies
{
classpath
"com.android.tools.build:gradle:$ANDROID_GRADLE_PLUGIN_VERSION"
classpath
"org.jetbrains.kotlin:kotlin-gradle-plugin:$KOTLIN_VERSION"
classpath
"org.jfrog.buildinfo:build-info-extractor-gradle:4.15.1"
classpath
"org.jetbrains.dokka:dokka-android-gradle-plugin:0.9.18"
}
}
...
...
@@ -55,7 +53,7 @@ allprojects {
apply
plugin:
'maven-publish'
repositories
{
google
()
jcenter
()
mavenCentral
()
maven
{
url
'https://nexus.frostnerd.com/repository/libs-release/'
credentials
{
...
...
gradle/wrapper/gradle-wrapper.properties
View file @
282f4783
...
...
@@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath
=
wrapper/dists
zipStoreBase
=
GRADLE_USER_HOME
zipStorePath
=
wrapper/dists
distributionUrl
=
https
\:
//services.gradle.org/distributions/gradle-
6.6
-all.zip
distributionUrl
=
https
\:
//services.gradle.org/distributions/gradle-
7.1.1
-all.zip
library/build.gradle
View file @
282f4783
apply
plugin:
'com.android.library'
apply
plugin:
'kotlin-android'
apply
plugin:
'kotlin-android-extensions'
apply
plugin:
'org.jetbrains.dokka-android'
group
=
'com.frostnerd.utilskt'
ext
{
libraryGroupId
=
'com.frostnerd.utilskt'
libraryArtifactId
=
'vpntunnelproxy'
libraryVersion
=
'3.1.
6
'
libraryGroupId
=
group
libraryArtifactId
=
rootProject
.
name
libraryVersion
=
'3.1.
17
'
}
android
{
...
...
@@ -64,10 +64,10 @@ dependencies {
implementation
"org.jetbrains.kotlin:kotlin-stdlib-jdk8:$KOTLIN_VERSION"
implementation
"org.jetbrains.kotlinx:kotlinx-coroutines-core:$COROUTINE_VERSION"
testImplementation
'junit:junit:4.13'
testImplementation
'junit:junit:4.13
.2
'
//testImplementation "org.robolectric:robolectric:$ROBOELECTRIC_VERSION"
androidTestImplementation
'androidx.test:runner:1.
2
.0'
androidTestImplementation
'androidx.test.espresso:espresso-core:3.
2
.0'
androidTestImplementation
'androidx.test:runner:1.
4
.0'
androidTestImplementation
'androidx.test.espresso:espresso-core:3.
4
.0'
}
configurations
.
all
{
...
...
@@ -79,16 +79,6 @@ task sourcesJar(type: Jar) {
classifier
=
'sources'
}
task
dokkaJavadoc
(
type:
org
.
jetbrains
.
dokka
.
gradle
.
DokkaTask
)
{
outputFormat
=
'javadoc'
outputDirectory
=
"$buildDir/javadoc"
}
task
javadocJar
(
type:
Jar
,
dependsOn:
dokkaJavadoc
)
{
classifier
=
'javadoc'
from
"$buildDir/javadoc"
}
afterEvaluate
{
publishing
{
publications
{
...
...
@@ -101,9 +91,6 @@ afterEvaluate {
artifact
(
sourcesJar
)
{
classifier
=
'sources'
}
artifact
(
javadocJar
)
{
classifier
=
'javadoc'
}
pom
.
withXml
{
def
dependenciesNode
=
asNode
().
appendNode
(
'dependencies'
)
...
...
@@ -130,4 +117,4 @@ afterEvaluate {
}
}
}
publish
.
dependsOn
(
"assembleRelease"
,
"sourcesJar"
,
"javadocJar"
)
\ No newline at end of file
publish
.
dependsOn
(
"assembleRelease"
,
"sourcesJar"
)
\ No newline at end of file
library/src/main/java/com/frostnerd/vpntunnelproxy/ForwardedPacketStore.kt
View file @
282f4783
...
...
@@ -11,7 +11,9 @@ import java.net.DatagramSocket
import
java.net.Socket
import
java.net.SocketException
import
java.util.*
import
java.util.concurrent.locks.ReentrantLock
import
kotlin.collections.ArrayList
import
kotlin.concurrent.withLock
/*
* Copyright (C) 2019 Daniel Wolf (Ch4t4r)
...
...
@@ -41,11 +43,14 @@ class ForwardedPacketStore(var logger: Logger?) {
private
val
_nonPollableForwardedPackets
:
LinkedList
<
FutureAnswer
>
=
LinkedList
()
private
val
newlyForwardedPackets
:
ArrayList
<
FutureAnswer
>
=
ArrayList
()
private
val
newlyForwardedNonPollablePackets
:
ArrayList
<
FutureAnswer
>
=
ArrayList
()
private
val
newPacketsLock
=
ReentrantLock
()
val
nonPollableForwardedPackets
:
List
<
FutureAnswer
>
=
_nonPollableForwardedPackets
val
forwardedPollablePackets
:
List
<
FutureAnswer
>
=
_forwardedPollablePackets
var
hasMixedAnswerType
:
Boolean
=
true
private
set
private
val
clearLock
=
Any
()
private
var
clearing
=
false
val
waitingAnswersSize
:
Int
get
()
=
forwardedPollablePackets
.
size
+
nonPollableForwardedPackets
.
size
+
newlyForwardedPackets
.
size
+
newlyForwardedNonPollablePackets
.
size
fun
addForwardedQuestion
(
token
:
DeviceWriteToken
,
socket
:
java
.
io
.
Closeable
)
{
addForwardedQuestion
(
SocketBasedFutureAnswer
(
token
,
socket
))
...
...
@@ -61,27 +66,33 @@ class ForwardedPacketStore(var logger: Logger?) {
@Throws
(
IOException
::
class
)
fun
addForwardedQuestion
(
futureAnswer
:
FutureAnswer
)
{
if
(
futureAnswer
.
isPollable
())
newlyForwardedPackets
.
add
(
futureAnswer
)
else
newlyForwardedNonPollablePackets
.
add
(
futureAnswer
)
newPacketsLock
.
withLock
{
if
(
futureAnswer
.
isPollable
())
newlyForwardedPackets
.
add
(
futureAnswer
)
else
newlyForwardedNonPollablePackets
.
add
(
futureAnswer
)
}
}
fun
processNewAnswers
(
pollable
:
Boolean
)
{
if
(
pollable
&&
newlyForwardedPackets
.
isNotEmpty
())
{
hasMixedAnswerType
=
newlyForwardedNonPollablePackets
.
isNotEmpty
()
for
(
packet
in
newlyForwardedPackets
)
{
packet
.
index
=
_forwardedPollablePackets
.
size
if
(
packet
.
isPollable
())
_forwardedPollablePackets
.
add
(
packet
)
else
_forwardedPollablePackets
.
add
(
packet
)
newPacketsLock
.
withLock
{
for
(
packet
in
newlyForwardedPackets
)
{
packet
.
index
=
_forwardedPollablePackets
.
size
if
(
packet
.
isPollable
())
_forwardedPollablePackets
.
add
(
packet
)
else
_forwardedPollablePackets
.
add
(
packet
)
}
newlyForwardedPackets
.
clear
()
}
newlyForwardedPackets
.
clear
()
}
else
if
(!
pollable
&&
newlyForwardedNonPollablePackets
.
isNotEmpty
())
{
hasMixedAnswerType
=
newlyForwardedPackets
.
isNotEmpty
()
for
(
packet
in
newlyForwardedNonPollablePackets
)
{
packet
.
index
=
_nonPollableForwardedPackets
.
size
if
(
packet
.
isPollable
())
_nonPollableForwardedPackets
.
add
(
packet
)
else
_nonPollableForwardedPackets
.
add
(
packet
)
newPacketsLock
.
withLock
{
hasMixedAnswerType
=
newlyForwardedPackets
.
isNotEmpty
()
for
(
packet
in
newlyForwardedNonPollablePackets
)
{
packet
.
index
=
_nonPollableForwardedPackets
.
size
if
(
packet
.
isPollable
())
_nonPollableForwardedPackets
.
add
(
packet
)
else
_nonPollableForwardedPackets
.
add
(
packet
)
}
newlyForwardedNonPollablePackets
.
clear
()
}
newlyForwardedNonPollablePackets
.
clear
()
}
}
...
...
@@ -92,26 +103,29 @@ class ForwardedPacketStore(var logger: Logger?) {
@Throws
(
IOException
::
class
)
fun
clear
(
completely
:
Boolean
=
false
)
{
if
(
clearing
)
return
clearing
=
true
logger
?.
fine
(
"Clearing ForwardedPacketStore"
)
synchronized
(
clearLock
)
{
forwardedPollablePackets
.
forEach
{
cleanup
(
it
)
}
_nonPollableForwardedPackets
.
forEach
{
cleanup
(
it
)
}
newPacketsLock
.
withLock
{
newlyForwardedPackets
.
forEach
{
cleanup
(
it
)
}
newlyForwardedNonPollablePackets
.
forEach
{
cleanup
(
it
)
}
_nonPollableForwardedPackets
.
clear
()
_forwardedPollablePackets
.
clear
()
newlyForwardedPackets
.
clear
()
newlyForwardedNonPollablePackets
.
clear
()
if
(
completely
)
logger
=
null
}
forwardedPollablePackets
.
forEach
{
cleanup
(
it
)
}
_nonPollableForwardedPackets
.
forEach
{
cleanup
(
it
)
}
_nonPollableForwardedPackets
.
clear
()
_forwardedPollablePackets
.
clear
()
clearing
=
false
if
(
completely
)
logger
=
null
}
}
...
...
@@ -196,13 +210,13 @@ open class SocketBasedFutureAnswer<T>(token: DeviceWriteToken,
val
inStream
=
DataInputStream
(
it
.
getInputStream
())
val
data
=
ByteArray
(
inStream
.
readUnsignedShort
())
val
actualRead
=
inStream
.
read
(
data
)
ReceivedAnswer
(
data
.
copyOf
(
actualRead
),
socket
,
actualRead
)
ReceivedAnswer
(
data
.
copyOf
(
actualRead
),
actualRead
)
}
is
DatagramSocket
->
{
val
datagramData
=
ByteArray
(
udpPacketSize
)
val
replyPacket
=
DatagramPacket
(
datagramData
,
datagramData
.
size
)
it
.
receive
(
replyPacket
)
ReceivedAnswer
(
datagramData
.
copyOf
(
replyPacket
.
length
)
,
socket
)
ReceivedAnswer
(
datagramData
.
copyOf
(
replyPacket
.
length
))
}
else
->
throw
IllegalStateException
()
}
...
...
@@ -251,13 +265,13 @@ abstract class SocketBasedNonPollableFutureAnswer<T>(token: DeviceWriteToken,
val
inStream
=
DataInputStream
(
it
.
getInputStream
())
val
data
=
ByteArray
(
inStream
.
readUnsignedShort
())
val
actualRead
=
inStream
.
read
(
data
)
ReceivedAnswer
(
data
.
copyOf
(
actualRead
),
socket
,
actualRead
)
ReceivedAnswer
(
data
.
copyOf
(
actualRead
),
actualRead
)
}
is
DatagramSocket
->
{
val
datagramData
=
ByteArray
(
udpPacketSize
)
val
replyPacket
=
DatagramPacket
(
datagramData
,
datagramData
.
size
)
it
.
receive
(
replyPacket
)
ReceivedAnswer
(
datagramData
.
copyOf
(
replyPacket
.
length
)
,
socket
)
ReceivedAnswer
(
datagramData
.
copyOf
(
replyPacket
.
length
))
}
else
->
throw
IllegalStateException
()
}
...
...
@@ -287,14 +301,13 @@ abstract class SocketBasedNonPollableFutureAnswer<T>(token: DeviceWriteToken,
open
class
Answer
internal
constructor
(
open
val
bytesTransferred
:
Int
)
data class
FailedAnswer
(
val
exception
:
Exception
):
Answer
(
0
)
data class
ReceivedAnswer
(
val
rawResponse
:
ByteArray
,
val
socket
:
Closeable
,
override
val
bytesTransferred
:
Int
=
rawResponse
.
size
):
Answer
(
bytesTransferred
)
{
data class
ReceivedAnswer
(
val
rawResponse
:
ByteArray
,
override
val
bytesTransferred
:
Int
=
rawResponse
.
size
):
Answer
(
bytesTransferred
)
{
override
fun
equals
(
other
:
Any
?):
Boolean
{
if
(
this
===
other
)
return
true
if
(
other
!
is
ReceivedAnswer
)
return
false
if
(!
rawResponse
.
contentEquals
(
other
.
rawResponse
))
return
false
if
(
socket
!=
other
.
socket
)
return
false
if
(
bytesTransferred
!=
other
.
bytesTransferred
)
return
false
return
true
...
...
@@ -302,8 +315,7 @@ data class ReceivedAnswer(val rawResponse: ByteArray, val socket: Closeable, ove
override
fun
hashCode
():
Int
{
var
result
=
rawResponse
.
contentHashCode
()
result
=
31
*
result
+
socket
.
hashCode
()
result
=
31
*
result
+
bytesTransferred
result
=
21
*
result
+
bytesTransferred
return
result
}
}
\ No newline at end of file
library/src/main/java/com/frostnerd/vpntunnelproxy/RetryingVPNTunnelProxy.kt
View file @
282f4783
...
...
@@ -80,7 +80,9 @@ class RetryingVPNTunnelProxy(packetProxy: PacketProxy,
lastCrash
=
System
.
currentTimeMillis
()
retryCount
++
if
(
retryCount
<
maxRetries
){
runProxyWithRetry
(
readEnd
,
writeEnd
)
afterCleanup
{
runProxyWithRetry
(
readEnd
,
writeEnd
)
}
}
else
{
throw
it
...
...
library/src/main/java/com/frostnerd/vpntunnelproxy/TrafficStats.kt
View file @
282f4783
...
...
@@ -30,6 +30,7 @@ open class TrafficStats(totalBytesRx: Long = 0,
bytesQueuedToDevice
:
Long
=
0
,
openSockets
:
Long
=
0
,
totalSockets
:
Long
=
0
)
{
internal
var
tunnelHandle
:
TunnelHandle
?
=
null
var
totalBytesRx
:
Long
=
totalBytesRx
internal
set
var
openSockets
:
Long
=
openSockets
...
...
@@ -55,6 +56,8 @@ open class TrafficStats(totalBytesRx: Long = 0,
var
failedAnswers
:
Long
=
0
internal
set
fun
memInfo
()
=
tunnelHandle
?.
memInfo
()
internal
fun
addLatency
(
oneLatency
:
Long
)
{
floatingAverageLatency
=
if
(
floatingAverageLatency
==
0L
)
oneLatency
else
{
...
...
library/src/main/java/com/frostnerd/vpntunnelproxy/TunnelHandle.kt
View file @
282f4783
...
...
@@ -50,6 +50,10 @@ class TunnelHandle(proxy: Proxy,
@Volatile
internal
var
needsLocking
:
Boolean
=
true
fun
memInfo
():
MemoryInfo
{
return
MemoryInfo
(
meta
.
size
,
byteOutput
.
size
,
byteOutput
.
sumOf
{
it
?.
size
?.
toLong
()
?:
0
},
forwardedPacketStore
?.
waitingAnswersSize
?:
0
)
}
fun
addMeta
(
token
:
DeviceWriteToken
,
data
:
Any
)
{
meta
[
token
.
index
]
=
data
}
...
...
@@ -133,3 +137,9 @@ class TunnelHandle(proxy: Proxy,
}
class
DeviceWriteToken
internal
constructor
(
internal
val
index
:
Int
)
data class
MemoryInfo
(
val
metaSize
:
Int
,
val
outputSize
:
Int
,
val
outputSizeBytes
:
Long
,
val
waitingPacketSize
:
Int
,
)
\ No newline at end of file
library/src/main/java/com/frostnerd/vpntunnelproxy/VPNTunnelProxy.kt
View file @
282f4783
...
...
@@ -14,7 +14,10 @@ import java.io.*
import
java.net.DatagramSocket
import
java.net.Socket
import
java.util.concurrent.locks.ReentrantLock
import
java.util.concurrent.locks.ReentrantReadWriteLock
import
kotlin.concurrent.read
import
kotlin.concurrent.withLock
import
kotlin.concurrent.write
/*
* Copyright (C) 2019 Daniel Wolf (Ch4t4r)
...
...
@@ -58,11 +61,16 @@ open class VPNTunnelProxy(val packetProxy: PacketProxy,
private
var
deviceOutput
:
FileOutputStream
?
=
null
private
var
tunnelHandle
:
TunnelHandle
?
=
null
private
var
exceptionCallbacks
=
mutableListOf
<(
Throwable
)
->
Unit
>()
private
var
cleanupCallbacks
=
mutableListOf
<()
->
Unit
>()
private
var
proxyThread
:
Thread
?
=
null
private
var
nonPollableProxyThread
:
Thread
?
=
null
@Volatile
private
var
polling
=
false
var
forwardingMode
:
ForwardingMode
=
ForwardingMode
.
MIXED
private
var
proxyThreadActive
:
Boolean
=
false
private
var
cleanupFinalized
:
Boolean
=
false
private
val
clearLock
=
ReentrantReadWriteLock
()
private
var
ioErrors
=
0
constructor
(
packetProxy
:
PacketProxy
,
trafficStats
:
TrafficStats
=
TrafficStats
(
0
,
0
),
...
...
@@ -95,6 +103,11 @@ open class VPNTunnelProxy(val packetProxy: PacketProxy,
exceptionCallbacks
.
add
(
callback
)
}
protected
fun
afterCleanup
(
callback
:()
->
Unit
)
{
if
(
cleanupFinalized
)
callback
()
else
cleanupCallbacks
.
add
(
callback
)
}
@Throws
(
IOException
::
class
,
ErrnoException
::
class
)
fun
run
(
tunnel
:
ParcelFileDescriptor
)
{
run
(
tunnel
,
tunnel
)
...
...
@@ -103,6 +116,7 @@ open class VPNTunnelProxy(val packetProxy: PacketProxy,
open
fun
run
(
readEnd
:
ParcelFileDescriptor
,
writeEnd
:
ParcelFileDescriptor
)
{
shouldRun
=
true
cleanupFinalized
=
false
logger
?.
info
(
"run() called."
)
val
errorStruct
=
createErrorPipe
()
logger
?.
info
(
"Creating device polls"
)
...
...
@@ -119,6 +133,7 @@ open class VPNTunnelProxy(val packetProxy: PacketProxy,
logger
?.
info
(
"Creating tunnel handle"
)
val
localPacketStore
=
forwardedPacketStore
?:
return
tunnelHandle
=
TunnelHandle
(
this
,
localPacketStore
,
trafficStats
)
trafficStats
.
tunnelHandle
=
tunnelHandle
packetProxy
.
injectTunnelHandle
(
tunnelHandle
!!
)
logger
?.
info
(
"Tunnel handle created"
)
...
...
@@ -129,7 +144,10 @@ open class VPNTunnelProxy(val packetProxy: PacketProxy,
val
eventsWriteBothActive
=
if
(
readEnd
==
writeEnd
)
0
else
OsConstants
.
POLLOUT
proxyThread
=
Thread
{
proxyThreadActive
=
true
logger
?.
info
(
"Proxy started on thread "
+
Thread
.
currentThread
().
name
)
val
lock
=
clearLock
.
readLock
()
lock
.
lock
()
try
{
try
{
while
(
shouldRun
)
{
...
...
@@ -158,9 +176,9 @@ open class VPNTunnelProxy(val packetProxy: PacketProxy,
logger
?.
info
(
"Device filed descriptors became invalid"
)
shouldRun
=
false
}
else
{
if
(
pollableAnswers
.
second
.
isNotEmpty
())
processFutureAnswers
(
pollableAnswers
.
second
,
true
)
if
(
deviceOutputPipe
.
actualEvent
(
OsConstants
.
POLLOUT
))
fromLoopbackToDevice
(
deviceOutput
)
// There is data in loopback
if
(
deviceInputPipe
.
actualEvent
(
OsConstants
.
POLLIN
))
fromDeviceToPacketProxy
(
deviceInput
)
if
(
pollableAnswers
.
second
.
isNotEmpty
())
tryIO
{
processFutureAnswers
(
pollableAnswers
.
second
,
true
)
}
if
(
deviceOutputPipe
.
actualEvent
(
OsConstants
.
POLLOUT
))
tryIO
{
fromLoopbackToDevice
(
deviceOutput
)
}
// There is data in loopback
if
(
deviceInputPipe
.
actualEvent
(
OsConstants
.
POLLIN
))
tryIO
{
fromDeviceToPacketProxy
(
deviceInput
)
}
Thread
.
sleep
(
1
)
}
}
else
if
(
shouldRun
)
{
...
...
@@ -181,11 +199,15 @@ open class VPNTunnelProxy(val packetProxy: PacketProxy,
}
finally
{
logger
?.
info
(
"Proxy thread ended."
)
proxyThreadActive
=
false
lock
.
unlock
()
finalizeCleanup
()
}
}
if
(
forwardingMode
!=
ForwardingMode
.
ONLY_POLLABLE
)
nonPollableProxyThread
=
Thread
{
logger
?.
info
(
"Non-pollable proxy started on thread "
+
Thread
.
currentThread
().
name
)
val
lock
=
clearLock
.
readLock
()
lock
.
lock
()
try
{
while
(
shouldRun
)
{
forwardedPacketStore
?.
processNewAnswers
(
false
)
...
...
@@ -205,6 +227,8 @@ open class VPNTunnelProxy(val packetProxy: PacketProxy,
}
catch
(
ex
:
java
.
lang
.
Exception
)
{
if
(
exceptionCallbacks
.
isEmpty
())
throw
ex
else
errorOccurred
(
ex
)
}
finally
{
lock
.
unlock
()
}
logger
?.
info
(
"Non-pollable proxy ended. Should run: $shouldRun"
)
}
...
...
@@ -213,6 +237,20 @@ open class VPNTunnelProxy(val packetProxy: PacketProxy,
logger
?.
info
(
"Done with run()."
)
}
private
fun
tryIO
(
block
:()
->
Unit
)
{
try
{
block
()
}
catch
(
ex
:
IOException
)
{
if
(
ex
is
InterruptedIOException
)
throw
ex
// Continued errors might indicate an underlying problem.
// either way, 100 is a lot and takes a lot of time to reach
// (besides, this error is again caught in another try)
if
(++
ioErrors
>=
100
)
{
throw
ex
}
}
}
private
val
packetFromDevice
=
ByteArray
(
32767
)
fun
fromDeviceToPacketProxy
(
deviceInput
:
InputStream
)
{
val
readSize
=
deviceInput
.
read
(
packetFromDevice
)
...
...
@@ -238,13 +276,11 @@ open class VPNTunnelProxy(val packetProxy: PacketProxy,
logger
?.
info
(
"stop() called"
)
if
(!
proxyStopped
)
{
proxyStopped
=
true
val
wasThreadRunning
=
proxyThread
?.
isAlive
?:
false
shouldRun
=
false
packetProxy
.
stop
()
cleanup
()
if
(!
wasThreadRunning
)
{
forwardedPacketStore
?.
clear
(
true
)
forwardedPacketStore
=
null
if
(!
proxyThreadActive
)
{
finalizeCleanup
()
}
tunnelHandle
?.
clear
(
true
)
tunnelHandle
=
null
...
...
@@ -255,6 +291,7 @@ open class VPNTunnelProxy(val packetProxy: PacketProxy,
private
fun
cleanup
()
{
logger
?.
info
{
"cleanup() called"
}
trafficStats
.
tunnelHandle
=
null
proxyThread
?.
interrupt
()
nonPollableProxyThread
?.
interrupt
()
exceptionCallbacks
.
clear
()
...
...
@@ -262,14 +299,19 @@ open class VPNTunnelProxy(val packetProxy: PacketProxy,
}
private
fun
finalizeCleanup
()
{
proxyThread
=
null
nonPollableProxyThread
=
null
for
(
fileDescriptor
in
pipesToClose
)
{
fileDescriptor
.
tryClosing
()
clearLock
.
write
{