mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-14 03:39:05 +01:00
Compare commits
159 Commits
release-1.
...
release-1.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a114d4db15 | ||
|
|
73b7879c64 | ||
|
|
e622a518ac | ||
|
|
28ea3d014a | ||
|
|
457d77ca51 | ||
|
|
581c67f5fd | ||
|
|
1dcb9aa1d0 | ||
|
|
d97dcfff30 | ||
|
|
e166d9dd15 | ||
|
|
2e002d132c | ||
|
|
da629df630 | ||
|
|
135372ebee | ||
|
|
b083122d72 | ||
|
|
649433a506 | ||
|
|
eff3a69734 | ||
|
|
62de50af76 | ||
|
|
1f9def8418 | ||
|
|
1e80069980 | ||
|
|
bfde71c151 | ||
|
|
bce0a3150b | ||
|
|
ee59b9b3ad | ||
|
|
55918a88b2 | ||
|
|
679c1c3719 | ||
|
|
21f33d6cfb | ||
|
|
912b1b5b1d | ||
|
|
0ad20037ae | ||
|
|
62d893f7b1 | ||
|
|
497213e56d | ||
|
|
f5c0d0b2cb | ||
|
|
f4131d6f32 | ||
|
|
06deba4bd4 | ||
|
|
26643e491b | ||
|
|
6ef4130f8f | ||
|
|
ba5b2f601b | ||
|
|
5be672f0e7 | ||
|
|
fa525564c0 | ||
|
|
dee0ca238b | ||
|
|
3c6b43b2bd | ||
|
|
dcacae0729 | ||
|
|
aefc5c519e | ||
|
|
7225adf24e | ||
|
|
30228cf025 | ||
|
|
99e2b7eaab | ||
|
|
2f7d5b869c | ||
|
|
d5d6db6723 | ||
|
|
b026031d66 | ||
|
|
abe14f19e6 | ||
|
|
fa17549972 | ||
|
|
0d2a91289f | ||
|
|
2e22318b27 | ||
|
|
11f0bd1ae0 | ||
|
|
e2d636e274 | ||
|
|
f41b76c567 | ||
|
|
08931e64cb | ||
|
|
ccee1febbc | ||
|
|
7bfc1c3579 | ||
|
|
2dc94a95ed | ||
|
|
a47a1cf442 | ||
|
|
4adb27a1ce | ||
|
|
841c31ebce | ||
|
|
d6810cf87f | ||
|
|
7a2df3d6cb | ||
|
|
0c65ff4783 | ||
|
|
8b10b7ed23 | ||
|
|
9743255ce9 | ||
|
|
c845dfc7f4 | ||
|
|
a8a02b9e45 | ||
|
|
6703be1c32 | ||
|
|
fc99dedb53 | ||
|
|
65a461a0db | ||
|
|
a44a68f231 | ||
|
|
4ac6baa23d | ||
|
|
4cde50b7f5 | ||
|
|
da40eca80b | ||
|
|
fa267d38af | ||
|
|
ba20fbeb47 | ||
|
|
196df05df9 | ||
|
|
44f07c8d76 | ||
|
|
d7f39af6d1 | ||
|
|
4f732c3997 | ||
|
|
74cfd313ab | ||
|
|
c089a099f0 | ||
|
|
98a0d09899 | ||
|
|
18c4195115 | ||
|
|
d4a9c41cf5 | ||
|
|
8bc28f99c1 | ||
|
|
1834146ad0 | ||
|
|
624e03a2c9 | ||
|
|
a24e0482c9 | ||
|
|
695b543ba9 | ||
|
|
75e910e1d9 | ||
|
|
8fc8333451 | ||
|
|
c2154c81f4 | ||
|
|
5cd5fc7e43 | ||
|
|
abd9db70b9 | ||
|
|
5025cf1e40 | ||
|
|
5e679e7a10 | ||
|
|
834342fd3a | ||
|
|
3028b236e1 | ||
|
|
254422bc02 | ||
|
|
c7949d6e00 | ||
|
|
0187264da7 | ||
|
|
85a18cf53f | ||
|
|
3181b695df | ||
|
|
b2ac210586 | ||
|
|
d20340416d | ||
|
|
9da871718c | ||
|
|
3793cb841b | ||
|
|
c6b88b51f0 | ||
|
|
2f00215a44 | ||
|
|
183f0c5f31 | ||
|
|
34c5aaae0a | ||
|
|
5531355ebd | ||
|
|
b9e607744a | ||
|
|
def62bce5a | ||
|
|
9dae3d191a | ||
|
|
20422edf78 | ||
|
|
f8bc5f08bf | ||
|
|
9434495d70 | ||
|
|
bf9e91fcf5 | ||
|
|
d9d86206a6 | ||
|
|
b410b8efcc | ||
|
|
39aa2d96b3 | ||
|
|
21dae824a6 | ||
|
|
cfdbd29cb4 | ||
|
|
4df335ebd3 | ||
|
|
682bee1486 | ||
|
|
f31219d54b | ||
|
|
b0ea32c85f | ||
|
|
651e0b9859 | ||
|
|
f66244b578 | ||
|
|
3a35effae9 | ||
|
|
97f4cd039a | ||
|
|
20a1474457 | ||
|
|
f214208b0a | ||
|
|
d95a5fd58c | ||
|
|
7d4de21be0 | ||
|
|
a65bda04bf | ||
|
|
41ae7b0522 | ||
|
|
c2214f5e61 | ||
|
|
75bd7927ac | ||
|
|
ed2c0336ed | ||
|
|
b23baf70b4 | ||
|
|
17a7144194 | ||
|
|
0f7d27cd95 | ||
|
|
6735e5075b | ||
|
|
135cf086f6 | ||
|
|
72bac59989 | ||
|
|
2c99a75b4e | ||
|
|
5c068ed07b | ||
|
|
fec384c200 | ||
|
|
89a4d1922b | ||
|
|
6ed16802ce | ||
|
|
7f11d7280f | ||
|
|
597e2a233f | ||
|
|
dcbb3e76d4 | ||
|
|
286937e472 | ||
|
|
a3b5ff0bc0 | ||
|
|
1192f66487 |
@@ -1,27 +1,31 @@
|
|||||||
image: registry.gitlab.com/fdroid/ci-images-base:latest
|
image: briar/ci-image-android:latest
|
||||||
|
|
||||||
cache:
|
|
||||||
paths:
|
|
||||||
- .gradle/wrapper
|
|
||||||
- .gradle/caches
|
|
||||||
|
|
||||||
before_script:
|
|
||||||
- set -e
|
|
||||||
- export GRADLE_USER_HOME=$PWD/.gradle
|
|
||||||
# Download OpenJDK 6 so we can compile against its standard library
|
|
||||||
- JDK_FILE=openjdk-6-jre-headless_6b38-1.13.10-1~deb7u1_amd64.deb
|
|
||||||
- if [ ! -d openjdk ]
|
|
||||||
- then
|
|
||||||
- wget -q http://ftp.uk.debian.org/debian/pool/main/o/openjdk-6/$JDK_FILE
|
|
||||||
- dpkg-deb -x $JDK_FILE openjdk
|
|
||||||
- fi
|
|
||||||
- export JAVA_6_HOME=$PWD/openjdk/usr/lib/jvm/java-6-openjdk-amd64
|
|
||||||
|
|
||||||
test:
|
test:
|
||||||
script:
|
before_script:
|
||||||
- ./gradlew test
|
- set -e
|
||||||
|
- export GRADLE_USER_HOME=$PWD/.gradle
|
||||||
|
|
||||||
after_script:
|
cache:
|
||||||
# this file changes every time but should not be cached
|
paths:
|
||||||
|
- .gradle/wrapper
|
||||||
|
- .gradle/caches
|
||||||
|
|
||||||
|
script:
|
||||||
|
- ./gradlew --no-daemon animalSnifferMain animalSnifferTest
|
||||||
|
- ./gradlew --no-daemon test
|
||||||
|
|
||||||
|
after_script:
|
||||||
|
# these file change every time but should not be cached
|
||||||
- rm -f $GRADLE_USER_HOME/caches/modules-2/modules-2.lock
|
- rm -f $GRADLE_USER_HOME/caches/modules-2/modules-2.lock
|
||||||
- rm -fr $GRADLE_USER_HOME/caches/*/plugin-resolution/
|
- rm -fr $GRADLE_USER_HOME/caches/*/plugin-resolution/
|
||||||
|
|
||||||
|
|
||||||
|
test_reproducible:
|
||||||
|
image: briar/reproducer:latest
|
||||||
|
|
||||||
|
script:
|
||||||
|
- cd /opt/briar-reproducer
|
||||||
|
- ./reproduce.py ${CI_COMMIT_REF_NAME}
|
||||||
|
|
||||||
|
only:
|
||||||
|
- tags
|
||||||
|
|||||||
@@ -1,11 +1,5 @@
|
|||||||
import de.undercouch.gradle.tasks.download.Download
|
|
||||||
import de.undercouch.gradle.tasks.download.Verify
|
|
||||||
|
|
||||||
import java.security.NoSuchAlgorithmException
|
|
||||||
|
|
||||||
apply plugin: 'com.android.library'
|
apply plugin: 'com.android.library'
|
||||||
apply plugin: 'witness'
|
apply plugin: 'witness'
|
||||||
apply plugin: 'de.undercouch.download'
|
|
||||||
|
|
||||||
android {
|
android {
|
||||||
compileSdkVersion 27
|
compileSdkVersion 27
|
||||||
@@ -14,8 +8,8 @@ android {
|
|||||||
defaultConfig {
|
defaultConfig {
|
||||||
minSdkVersion 14
|
minSdkVersion 14
|
||||||
targetSdkVersion 26
|
targetSdkVersion 26
|
||||||
versionCode 10003
|
versionCode 10011
|
||||||
versionName "1.0.3"
|
versionName "1.0.11"
|
||||||
consumerProguardFiles 'proguard-rules.txt'
|
consumerProguardFiles 'proguard-rules.txt'
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -25,9 +19,14 @@ android {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
configurations {
|
||||||
|
tor
|
||||||
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation project(path: ':bramble-core', configuration: 'default')
|
implementation project(path: ':bramble-core', configuration: 'default')
|
||||||
implementation fileTree(dir: 'libs', include: '*.jar')
|
implementation 'org.briarproject:jtorctl:0.3'
|
||||||
|
tor 'org.briarproject:tor-android:0.2.9.15@zip'
|
||||||
|
|
||||||
annotationProcessor 'com.google.dagger:dagger-compiler:2.0.2'
|
annotationProcessor 'com.google.dagger:dagger-compiler:2.0.2'
|
||||||
|
|
||||||
@@ -36,32 +35,32 @@ dependencies {
|
|||||||
|
|
||||||
dependencyVerification {
|
dependencyVerification {
|
||||||
verify = [
|
verify = [
|
||||||
'com.android.tools.analytics-library:protos:26.1.2:protos-26.1.2.jar:52672a0b42b572a06aecc3535d5068eb46c0e15d129b9f1085d3c16a1da5cdbb',
|
'com.android.tools.analytics-library:protos:26.1.3:protos-26.1.3.jar:818c9f256f141d9dafec03a1aa2b94d240b2c140acfd7ee31a8b3e6c2b9479e3',
|
||||||
'com.android.tools.analytics-library:shared:26.1.2:shared-26.1.2.jar:5c7e0eda18c6f87feeb83628c707e8aaa3298b41fb72e38efe31ad1675f9e8e9',
|
'com.android.tools.analytics-library:shared:26.1.3:shared-26.1.3.jar:7110706c7ada96c8b6f5ca80c478291bc7899d46277de2c48527e045442401a3',
|
||||||
'com.android.tools.analytics-library:tracker:26.1.2:tracker-26.1.2.jar:06f97aa0adf44ffb06f8681c6a79d9be153a08f61d21eddc42b8d3db96df4282',
|
'com.android.tools.analytics-library:tracker:26.1.3:tracker-26.1.3.jar:4155424bf2ce4872da83332579a1707252bc66cbd77c5144fdc4483d0f2e1418',
|
||||||
'com.android.tools.build:apksig:3.1.2:apksig-3.1.2.jar:40696a4559124d1d57873d208857eee059d48859239d569c7d18374ac644a8be',
|
'com.android.tools.build:apksig:3.1.3:apksig-3.1.3.jar:7e1f8e675a6e768e5b56405e41d6c3cc05befe62e601b04177de1029902c9c89',
|
||||||
'com.android.tools.build:builder-model:3.1.2:builder-model-3.1.2.jar:d49bfa2a135c9562b6ca7aa4342036cfa1582c7074c2d1d93d1dae8b3a134e17',
|
'com.android.tools.build:builder-model:3.1.3:builder-model-3.1.3.jar:06ad1c422d679fc698451479cb40ba863849d67bfd1de23f6d2c16d78b024b0b',
|
||||||
'com.android.tools.build:builder-test-api:3.1.2:builder-test-api-3.1.2.jar:dfe2a50b740d41b11189101062434d4283d18647e89a492ad51710c719363e9f',
|
'com.android.tools.build:builder-test-api:3.1.3:builder-test-api-3.1.3.jar:4d989f780436794f0f8b2f50e9e079b786571eac90f26c208ab2ae6d4012f389',
|
||||||
'com.android.tools.build:builder:3.1.2:builder-3.1.2.jar:b60f825a42e2efe8433619fbc759f3d9effecab718279048d36881188ceb1d14',
|
'com.android.tools.build:builder:3.1.3:builder-3.1.3.jar:8a1092012c89d0ec1ee2eff09c5708c71ef4482a6862df8d3a44a67fccace01c',
|
||||||
'com.android.tools.build:gradle-api:3.1.2:gradle-api-3.1.2.jar:e58bcc5b893e4583ab0f5c8ef89c4dbcce202b405a9d7fcc116d21e5357d4893',
|
'com.android.tools.build:gradle-api:3.1.3:gradle-api-3.1.3.jar:01e4df521456aef66514336f1d492346730dd1fb8f6433a89f62da834941ed72',
|
||||||
'com.android.tools.build:manifest-merger:26.1.2:manifest-merger-26.1.2.jar:9c61c27ea5266573107b954acf1216d398f4d7e7ae6fad6409d6b2b767eb091c',
|
'com.android.tools.build:manifest-merger:26.1.3:manifest-merger-26.1.3.jar:1e4fc7e932adb4607082409800e5e6fccb42e6c5360ae5990094bf522f3ada55',
|
||||||
'com.android.tools.ddms:ddmlib:26.1.2:ddmlib-26.1.2.jar:18a2a5fbef36882f07d03c2b9e59eba05cf8248177bf5cbff736e4b582804c44',
|
'com.android.tools.ddms:ddmlib:26.1.3:ddmlib-26.1.3.jar:c54931cd68df5d1ea2923b3b320eae47cd2307a5a916bb8674c0acf93cd1d3cd',
|
||||||
'com.android.tools.external.com-intellij:intellij-core:26.1.2:intellij-core-26.1.2.jar:37c5acf279f1ae3e85b1a5be3c9f15f43bde7b08f978eefefffb9c4035760c52',
|
'com.android.tools.external.com-intellij:intellij-core:26.1.3:intellij-core-26.1.3.jar:af67f5535fef2e1a28b1007a4acb8c5deb6a1e33b8afe7b11d012c9e778ebcec',
|
||||||
'com.android.tools.external.com-intellij:kotlin-compiler:26.1.2:kotlin-compiler-26.1.2.jar:152df0bee7580326c77316b669a9d96e3b09efb1d45f545dce4147271b0b8944',
|
'com.android.tools.external.com-intellij:kotlin-compiler:26.1.3:kotlin-compiler-26.1.3.jar:c746d2859dc11cc05c84b692b3498d3a621e0929511f8440ee009c6557838fd4',
|
||||||
'com.android.tools.external.org-jetbrains:uast:26.1.2:uast-26.1.2.jar:02d39582206d3f5fc0a6cb18bfd9e8b9f9c1acb805ec6dac08b4e3a56849d279',
|
'com.android.tools.external.org-jetbrains:uast:26.1.3:uast-26.1.3.jar:3f3f6651d0c7685a77ecb22e9c82d6b49fdf24322c17360768dc530678f43265',
|
||||||
'com.android.tools.layoutlib:layoutlib-api:26.1.2:layoutlib-api-26.1.2.jar:20220039fcc7d799f928153beff862e704457c0f55ab44258f3745ebeb662b4f',
|
'com.android.tools.layoutlib:layoutlib-api:26.1.3:layoutlib-api-26.1.3.jar:10bc73ce706c45629872d6a999dbe12116df64e24f47ff93b7b13121ff57b4b0',
|
||||||
'com.android.tools.lint:lint-api:26.1.2:lint-api-26.1.2.jar:e1d5b62b870a7c566e9877a6b96b27784a4d713f8caa07fdcb4705d47a40a1d9',
|
'com.android.tools.lint:lint-api:26.1.3:lint-api-26.1.3.jar:6f97323f9af8deda86278717885b5c927f3766757db89709f52d11d42b6fb751',
|
||||||
'com.android.tools.lint:lint-checks:26.1.2:lint-checks-26.1.2.jar:211e2afd58504372385d71b1e5be982c2b5121ab6fee1c04ddabeb75a8729e07',
|
'com.android.tools.lint:lint-checks:26.1.3:lint-checks-26.1.3.jar:73c3d53784c9ce3e6d5968506581918e0179645d20809927ca4a001dd766b001',
|
||||||
'com.android.tools.lint:lint-gradle-api:26.1.2:lint-gradle-api-26.1.2.jar:71284f2a8b03c3e55c94511c9eb36f8184fbb85324325fc6b78abf5183f03d90',
|
'com.android.tools.lint:lint-gradle-api:26.1.3:lint-gradle-api-26.1.3.jar:7ca3c4866ec21dc21d53a9d86f752b77ace6f6c610a0c9dc877313856c733d9d',
|
||||||
'com.android.tools.lint:lint-gradle:26.1.2:lint-gradle-26.1.2.jar:855f0c82b7fc690df1b7319c0774f7517f7f8f5dd4eee1f6077dcf50e07c6240',
|
'com.android.tools.lint:lint-gradle:26.1.3:lint-gradle-26.1.3.jar:db0c354b8f4b6f6637e31f91c564785a59ff896325331fcbc3de7458e0b6c067',
|
||||||
'com.android.tools.lint:lint-kotlin:26.1.2:lint-kotlin-26.1.2.jar:1e591f70bcbbc11569720a9bbcca2bc1f3d4f789f01f40f642848d920643d484',
|
'com.android.tools.lint:lint-kotlin:26.1.3:lint-kotlin-26.1.3.jar:94e2b0f4565a241561cfb8fc1222bb3f132a3b98d2a90421dbb72ee8358e7d68',
|
||||||
'com.android.tools.lint:lint:26.1.2:lint-26.1.2.jar:93736c62e9f1976998c2b4aa716aea0734cdb162d05502f4af7292654aedb182',
|
'com.android.tools.lint:lint:26.1.3:lint-26.1.3.jar:8d5f32c989c6d191d712e90ad3ca2d1c409313599551d04d834caa44d26c78df',
|
||||||
'com.android.tools:annotations:26.1.2:annotations-26.1.2.jar:72773dcaf5c4ccca828e3c8467f1b78a8a00b3cc5f8ad1aab88fcf9379928018',
|
'com.android.tools:annotations:26.1.3:annotations-26.1.3.jar:c950430b24ac5d58fc97e7283b8f0115f99587e76e08b4e1e2aaa780f2d77323',
|
||||||
'com.android.tools:common:26.1.2:common-26.1.2.jar:ea4320f0c17dcbc4491896bb705c4d25ec08bd62ef02ab0579fe154e75e788e6',
|
'com.android.tools:common:26.1.3:common-26.1.3.jar:7c31a90581a148ab219f615a59667f0dded7fa39b248529784474da3c2274ef2',
|
||||||
'com.android.tools:dvlib:26.1.2:dvlib-26.1.2.jar:1187aa4fb666595c96c4deb6bc0e0f4b7e396bde9f6243330b49a232946130ea',
|
'com.android.tools:dvlib:26.1.3:dvlib-26.1.3.jar:0cae87906f53d3f1088366a916ed180a7312b6d9919b90797f238875c8492855',
|
||||||
'com.android.tools:repository:26.1.2:repository-26.1.2.jar:8b86e512ad6d32bd76989451eefe2b271f5efce6d4d65ecb173afaf14606e01a',
|
'com.android.tools:repository:26.1.3:repository-26.1.3.jar:52d4539cc68db91b261e2a33b2c8206b26e05539078758dc28cfb3854adb4f59',
|
||||||
'com.android.tools:sdk-common:26.1.2:sdk-common-26.1.2.jar:23584720a60a21cdcb5b1ec10269e3013789d6805d153cc696c39ec7ce251896',
|
'com.android.tools:sdk-common:26.1.3:sdk-common-26.1.3.jar:1948603ca9ff22c7ebb3178000bffa3a9dd2ca1cc5cb0c793cae08468b8fcfc1',
|
||||||
'com.android.tools:sdklib:26.1.2:sdklib-26.1.2.jar:d3870fafc59ab8efa70d3f9649f40ee299c8ec5b58377b06e8853d7272a5bf4e',
|
'com.android.tools:sdklib:26.1.3:sdklib-26.1.3.jar:4adcfaad9514607098d2c51503c39811112d3050f4d1e744c01c7f08f591032b',
|
||||||
'com.google.code.findbugs:jsr305:1.3.9:jsr305-1.3.9.jar:905721a0eea90a81534abb7ee6ef4ea2e5e645fa1def0a5cd88402df1b46c9ed',
|
'com.google.code.findbugs:jsr305:1.3.9:jsr305-1.3.9.jar:905721a0eea90a81534abb7ee6ef4ea2e5e645fa1def0a5cd88402df1b46c9ed',
|
||||||
'com.google.code.gson:gson:2.7:gson-2.7.jar:2d43eb5ea9e133d2ee2405cc14f5ee08951b8361302fdd93494a3a997b508d32',
|
'com.google.code.gson:gson:2.7:gson-2.7.jar:2d43eb5ea9e133d2ee2405cc14f5ee08951b8361302fdd93494a3a997b508d32',
|
||||||
'com.google.dagger:dagger-compiler:2.0.2:dagger-compiler-2.0.2.jar:b74bc9de063dd4c6400b232231f2ef5056145b8fbecbf5382012007dd1c071b3',
|
'com.google.dagger:dagger-compiler:2.0.2:dagger-compiler-2.0.2.jar:b74bc9de063dd4c6400b232231f2ef5056145b8fbecbf5382012007dd1c071b3',
|
||||||
@@ -92,6 +91,8 @@ dependencyVerification {
|
|||||||
'org.apache.httpcomponents:httpmime:4.1:httpmime-4.1.jar:31629566148e8a47688ae43b420abc3ecd783ed15b33bebc00824bf24c9b15aa',
|
'org.apache.httpcomponents:httpmime:4.1:httpmime-4.1.jar:31629566148e8a47688ae43b420abc3ecd783ed15b33bebc00824bf24c9b15aa',
|
||||||
'org.bouncycastle:bcpkix-jdk15on:1.56:bcpkix-jdk15on-1.56.jar:7043dee4e9e7175e93e0b36f45b1ec1ecb893c5f755667e8b916eb8dd201c6ca',
|
'org.bouncycastle:bcpkix-jdk15on:1.56:bcpkix-jdk15on-1.56.jar:7043dee4e9e7175e93e0b36f45b1ec1ecb893c5f755667e8b916eb8dd201c6ca',
|
||||||
'org.bouncycastle:bcprov-jdk15on:1.56:bcprov-jdk15on-1.56.jar:963e1ee14f808ffb99897d848ddcdb28fa91ddda867eb18d303e82728f878349',
|
'org.bouncycastle:bcprov-jdk15on:1.56:bcprov-jdk15on-1.56.jar:963e1ee14f808ffb99897d848ddcdb28fa91ddda867eb18d303e82728f878349',
|
||||||
|
'org.briarproject:jtorctl:0.3:jtorctl-0.3.jar:f2939238a097898998432effe93b0334d97a787972ab3a91a8973a1d309fc864',
|
||||||
|
'org.briarproject:tor-android:0.2.9.15:tor-android-0.2.9.15.zip:34a6474ee219ffa52e0f3393e917dda6ed03d320b02247d4fa5075aa4094ee6d',
|
||||||
'org.codehaus.groovy:groovy-all:2.4.12:groovy-all-2.4.12.jar:6a56af4bd48903d56bec62821876cadefafd007360cc6bd0d8f7aa8d72b38be4',
|
'org.codehaus.groovy:groovy-all:2.4.12:groovy-all-2.4.12.jar:6a56af4bd48903d56bec62821876cadefafd007360cc6bd0d8f7aa8d72b38be4',
|
||||||
'org.codehaus.mojo:animal-sniffer-annotations:1.14:animal-sniffer-annotations-1.14.jar:2068320bd6bad744c3673ab048f67e30bef8f518996fa380033556600669905d',
|
'org.codehaus.mojo:animal-sniffer-annotations:1.14:animal-sniffer-annotations-1.14.jar:2068320bd6bad744c3673ab048f67e30bef8f518996fa380033556600669905d',
|
||||||
'org.glassfish.jaxb:jaxb-core:2.2.11:jaxb-core-2.2.11.jar:37bcaee8ebb04362c8352a5bf6221b86967ecdab5164c696b10b9a2bb587b2aa',
|
'org.glassfish.jaxb:jaxb-core:2.2.11:jaxb-core-2.2.11.jar:37bcaee8ebb04362c8352a5bf6221b86967ecdab5164c696b10b9a2bb587b2aa',
|
||||||
@@ -112,81 +113,9 @@ dependencyVerification {
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
ext.torBinaryDir = 'src/main/res/raw'
|
|
||||||
ext.torVersion = '0.2.9.14'
|
|
||||||
ext.geoipVersion = '2017-11-06'
|
|
||||||
ext.torDownloadUrl = 'https://briarproject.org/build/'
|
|
||||||
|
|
||||||
def torBinaries = [
|
|
||||||
"tor_arm" : '1710ea6c47b7f4c1a88bdf4858c7893837635db10e8866854eed8d61629f50e8',
|
|
||||||
"tor_arm_pie": '974e6949507db8fa2ea45231817c2c3677ed4ccf5488a2252317d744b0be1917',
|
|
||||||
"tor_x86" : '3a5e45b3f051fcda9353b098b7086e762ffe7ba9242f7d7c8bf6523faaa8b1e9',
|
|
||||||
"tor_x86_pie": 'd1d96d8ce1a4b68accf04850185780d10cd5563d3552f7e1f040f8ca32cb4e51',
|
|
||||||
"geoip" : '8239b98374493529a29096e45fc5877d4d6fdad0146ad8380b291f90d61484ea'
|
|
||||||
]
|
|
||||||
|
|
||||||
def verifyOrDeleteBinary(name, chksum, alreadyVerified) {
|
|
||||||
return tasks.create("verifyOrDeleteBinary${name}", VerifyOrDelete) {
|
|
||||||
src "${torBinaryDir}/${name}.zip"
|
|
||||||
algorithm 'SHA-256'
|
|
||||||
checksum chksum
|
|
||||||
result alreadyVerified
|
|
||||||
onlyIf {
|
|
||||||
src.exists()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def downloadBinary(name, chksum, alreadyVerified) {
|
|
||||||
return tasks.create([
|
|
||||||
name: "downloadBinary${name}",
|
|
||||||
type: Download,
|
|
||||||
dependsOn: verifyOrDeleteBinary(name, chksum, alreadyVerified)]) {
|
|
||||||
src "${torDownloadUrl}${name}.zip"
|
|
||||||
.replace('tor_', "tor-${torVersion}-")
|
|
||||||
.replace('geoip', "geoip-${geoipVersion}")
|
|
||||||
.replaceAll('_', '-')
|
|
||||||
dest "${torBinaryDir}/${name}.zip"
|
|
||||||
onlyIf {
|
|
||||||
!dest.exists()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def verifyBinary(name, chksum) {
|
|
||||||
boolean[] alreadyVerified = [false]
|
|
||||||
return tasks.create([
|
|
||||||
name : "verifyBinary${name}",
|
|
||||||
type : Verify,
|
|
||||||
dependsOn: downloadBinary(name, chksum, alreadyVerified)]) {
|
|
||||||
src "${torBinaryDir}/${name}.zip"
|
|
||||||
algorithm 'SHA-256'
|
|
||||||
checksum chksum
|
|
||||||
onlyIf {
|
|
||||||
!alreadyVerified[0]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
project.afterEvaluate {
|
project.afterEvaluate {
|
||||||
torBinaries.every { name, checksum ->
|
copy {
|
||||||
preBuild.dependsOn.add(verifyBinary(name, checksum))
|
from configurations.tor.collect { zipTree(it) }
|
||||||
}
|
into 'src/main/res/raw'
|
||||||
}
|
|
||||||
|
|
||||||
class VerifyOrDelete extends Verify {
|
|
||||||
|
|
||||||
boolean[] result
|
|
||||||
|
|
||||||
@TaskAction
|
|
||||||
@Override
|
|
||||||
void verify() throws IOException, NoSuchAlgorithmException {
|
|
||||||
try {
|
|
||||||
super.verify()
|
|
||||||
result[0] = true
|
|
||||||
} catch (Exception e) {
|
|
||||||
println "${src} failed verification - deleting"
|
|
||||||
src.delete()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Binary file not shown.
@@ -1,12 +1,10 @@
|
|||||||
package org.briarproject.bramble;
|
package org.briarproject.bramble;
|
||||||
|
|
||||||
import org.briarproject.bramble.plugin.AndroidPluginModule;
|
|
||||||
import org.briarproject.bramble.system.AndroidSystemModule;
|
import org.briarproject.bramble.system.AndroidSystemModule;
|
||||||
|
|
||||||
import dagger.Module;
|
import dagger.Module;
|
||||||
|
|
||||||
@Module(includes = {
|
@Module(includes = {
|
||||||
AndroidPluginModule.class,
|
|
||||||
AndroidSystemModule.class
|
AndroidSystemModule.class
|
||||||
})
|
})
|
||||||
public class BrambleAndroidModule {
|
public class BrambleAndroidModule {
|
||||||
|
|||||||
@@ -1,69 +0,0 @@
|
|||||||
package org.briarproject.bramble.plugin;
|
|
||||||
|
|
||||||
import android.app.Application;
|
|
||||||
import android.content.Context;
|
|
||||||
|
|
||||||
import org.briarproject.bramble.api.event.EventBus;
|
|
||||||
import org.briarproject.bramble.api.lifecycle.IoExecutor;
|
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
|
||||||
import org.briarproject.bramble.api.plugin.BackoffFactory;
|
|
||||||
import org.briarproject.bramble.api.plugin.PluginConfig;
|
|
||||||
import org.briarproject.bramble.api.plugin.duplex.DuplexPluginFactory;
|
|
||||||
import org.briarproject.bramble.api.plugin.simplex.SimplexPluginFactory;
|
|
||||||
import org.briarproject.bramble.api.reporting.DevReporter;
|
|
||||||
import org.briarproject.bramble.api.system.AndroidExecutor;
|
|
||||||
import org.briarproject.bramble.api.system.LocationUtils;
|
|
||||||
import org.briarproject.bramble.api.system.Scheduler;
|
|
||||||
import org.briarproject.bramble.plugin.bluetooth.AndroidBluetoothPluginFactory;
|
|
||||||
import org.briarproject.bramble.plugin.tcp.AndroidLanTcpPluginFactory;
|
|
||||||
import org.briarproject.bramble.plugin.tor.TorPluginFactory;
|
|
||||||
|
|
||||||
import java.security.SecureRandom;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.concurrent.Executor;
|
|
||||||
import java.util.concurrent.ScheduledExecutorService;
|
|
||||||
|
|
||||||
import javax.net.SocketFactory;
|
|
||||||
|
|
||||||
import dagger.Module;
|
|
||||||
import dagger.Provides;
|
|
||||||
|
|
||||||
@Module
|
|
||||||
public class AndroidPluginModule {
|
|
||||||
|
|
||||||
@Provides
|
|
||||||
PluginConfig providePluginConfig(@IoExecutor Executor ioExecutor,
|
|
||||||
@Scheduler ScheduledExecutorService scheduler,
|
|
||||||
AndroidExecutor androidExecutor, SecureRandom random,
|
|
||||||
SocketFactory torSocketFactory, BackoffFactory backoffFactory,
|
|
||||||
Application app, LocationUtils locationUtils, DevReporter reporter,
|
|
||||||
EventBus eventBus) {
|
|
||||||
Context appContext = app.getApplicationContext();
|
|
||||||
DuplexPluginFactory bluetooth =
|
|
||||||
new AndroidBluetoothPluginFactory(ioExecutor, androidExecutor,
|
|
||||||
appContext, random, eventBus, backoffFactory);
|
|
||||||
DuplexPluginFactory tor = new TorPluginFactory(ioExecutor, scheduler,
|
|
||||||
appContext, locationUtils, reporter, eventBus,
|
|
||||||
torSocketFactory, backoffFactory);
|
|
||||||
DuplexPluginFactory lan = new AndroidLanTcpPluginFactory(ioExecutor,
|
|
||||||
scheduler, backoffFactory, appContext);
|
|
||||||
Collection<DuplexPluginFactory> duplex =
|
|
||||||
Arrays.asList(bluetooth, tor, lan);
|
|
||||||
@NotNullByDefault
|
|
||||||
PluginConfig pluginConfig = new PluginConfig() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Collection<DuplexPluginFactory> getDuplexFactories() {
|
|
||||||
return duplex;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Collection<SimplexPluginFactory> getSimplexFactories() {
|
|
||||||
return Collections.emptyList();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
return pluginConfig;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -38,6 +38,7 @@ import static android.bluetooth.BluetoothAdapter.SCAN_MODE_NONE;
|
|||||||
import static android.bluetooth.BluetoothAdapter.STATE_OFF;
|
import static android.bluetooth.BluetoothAdapter.STATE_OFF;
|
||||||
import static android.bluetooth.BluetoothAdapter.STATE_ON;
|
import static android.bluetooth.BluetoothAdapter.STATE_ON;
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
|
import static org.briarproject.bramble.util.LogUtils.logException;
|
||||||
|
|
||||||
@MethodsNotNullByDefault
|
@MethodsNotNullByDefault
|
||||||
@ParametersNotNullByDefault
|
@ParametersNotNullByDefault
|
||||||
@@ -145,7 +146,7 @@ class AndroidBluetoothPlugin extends BluetoothPlugin<BluetoothServerSocket> {
|
|||||||
try {
|
try {
|
||||||
if (ss != null) ss.close();
|
if (ss != null) ss.close();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
logException(LOG, WARNING, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -185,7 +186,7 @@ class AndroidBluetoothPlugin extends BluetoothPlugin<BluetoothServerSocket> {
|
|||||||
try {
|
try {
|
||||||
if (c != null) c.close();
|
if (c != null) c.close();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
logException(LOG, WARNING, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ import android.content.pm.PackageManager.NameNotFoundException;
|
|||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
||||||
import android.net.ConnectivityManager;
|
import android.net.ConnectivityManager;
|
||||||
import android.net.NetworkInfo;
|
import android.net.NetworkInfo;
|
||||||
import android.os.FileObserver;
|
|
||||||
import android.os.PowerManager;
|
import android.os.PowerManager;
|
||||||
|
|
||||||
import net.freehaven.tor.control.EventHandler;
|
import net.freehaven.tor.control.EventHandler;
|
||||||
@@ -32,12 +31,12 @@ import org.briarproject.bramble.api.plugin.duplex.DuplexPlugin;
|
|||||||
import org.briarproject.bramble.api.plugin.duplex.DuplexPluginCallback;
|
import org.briarproject.bramble.api.plugin.duplex.DuplexPluginCallback;
|
||||||
import org.briarproject.bramble.api.plugin.duplex.DuplexTransportConnection;
|
import org.briarproject.bramble.api.plugin.duplex.DuplexTransportConnection;
|
||||||
import org.briarproject.bramble.api.properties.TransportProperties;
|
import org.briarproject.bramble.api.properties.TransportProperties;
|
||||||
import org.briarproject.bramble.api.reporting.DevReporter;
|
|
||||||
import org.briarproject.bramble.api.settings.Settings;
|
import org.briarproject.bramble.api.settings.Settings;
|
||||||
import org.briarproject.bramble.api.settings.event.SettingsUpdatedEvent;
|
import org.briarproject.bramble.api.settings.event.SettingsUpdatedEvent;
|
||||||
|
import org.briarproject.bramble.api.system.Clock;
|
||||||
import org.briarproject.bramble.api.system.LocationUtils;
|
import org.briarproject.bramble.api.system.LocationUtils;
|
||||||
import org.briarproject.bramble.util.AndroidUtils;
|
|
||||||
import org.briarproject.bramble.util.IoUtils;
|
import org.briarproject.bramble.util.IoUtils;
|
||||||
|
import org.briarproject.bramble.util.RenewableWakeLock;
|
||||||
import org.briarproject.bramble.util.StringUtils;
|
import org.briarproject.bramble.util.StringUtils;
|
||||||
|
|
||||||
import java.io.Closeable;
|
import java.io.Closeable;
|
||||||
@@ -52,13 +51,11 @@ import java.net.InetSocketAddress;
|
|||||||
import java.net.ServerSocket;
|
import java.net.ServerSocket;
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
import java.util.Scanner;
|
import java.util.Scanner;
|
||||||
import java.util.concurrent.CountDownLatch;
|
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
import java.util.concurrent.Future;
|
import java.util.concurrent.Future;
|
||||||
import java.util.concurrent.ScheduledExecutorService;
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
@@ -81,7 +78,6 @@ import static android.net.ConnectivityManager.TYPE_WIFI;
|
|||||||
import static android.os.Build.VERSION.SDK_INT;
|
import static android.os.Build.VERSION.SDK_INT;
|
||||||
import static android.os.PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED;
|
import static android.os.PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED;
|
||||||
import static android.os.PowerManager.PARTIAL_WAKE_LOCK;
|
import static android.os.PowerManager.PARTIAL_WAKE_LOCK;
|
||||||
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
|
||||||
import static java.util.concurrent.TimeUnit.MINUTES;
|
import static java.util.concurrent.TimeUnit.MINUTES;
|
||||||
import static java.util.logging.Level.INFO;
|
import static java.util.logging.Level.INFO;
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
@@ -95,6 +91,7 @@ import static org.briarproject.bramble.api.plugin.TorConstants.PREF_TOR_NETWORK_
|
|||||||
import static org.briarproject.bramble.api.plugin.TorConstants.PREF_TOR_NETWORK_WIFI;
|
import static org.briarproject.bramble.api.plugin.TorConstants.PREF_TOR_NETWORK_WIFI;
|
||||||
import static org.briarproject.bramble.api.plugin.TorConstants.PREF_TOR_PORT;
|
import static org.briarproject.bramble.api.plugin.TorConstants.PREF_TOR_PORT;
|
||||||
import static org.briarproject.bramble.api.plugin.TorConstants.PROP_ONION;
|
import static org.briarproject.bramble.api.plugin.TorConstants.PROP_ONION;
|
||||||
|
import static org.briarproject.bramble.util.LogUtils.logException;
|
||||||
import static org.briarproject.bramble.util.PrivacyUtils.scrubOnion;
|
import static org.briarproject.bramble.util.PrivacyUtils.scrubOnion;
|
||||||
|
|
||||||
@MethodsNotNullByDefault
|
@MethodsNotNullByDefault
|
||||||
@@ -105,8 +102,11 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
|||||||
"CIRC", "ORCONN", "HS_DESC", "NOTICE", "WARN", "ERR"
|
"CIRC", "ORCONN", "HS_DESC", "NOTICE", "WARN", "ERR"
|
||||||
};
|
};
|
||||||
private static final String OWNER = "__OwningControllerProcess";
|
private static final String OWNER = "__OwningControllerProcess";
|
||||||
private static final int COOKIE_TIMEOUT = 3000; // Milliseconds
|
private static final int COOKIE_TIMEOUT_MS = 3000;
|
||||||
|
private static final int COOKIE_POLLING_INTERVAL_MS = 200;
|
||||||
private static final Pattern ONION = Pattern.compile("[a-z2-7]{16}");
|
private static final Pattern ONION = Pattern.compile("[a-z2-7]{16}");
|
||||||
|
// This tag may prevent Huawei's power manager from killing us
|
||||||
|
private static final String WAKE_LOCK_TAG = "LocationManagerService";
|
||||||
private static final Logger LOG =
|
private static final Logger LOG =
|
||||||
Logger.getLogger(TorPlugin.class.getName());
|
Logger.getLogger(TorPlugin.class.getName());
|
||||||
|
|
||||||
@@ -114,8 +114,8 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
|||||||
private final ScheduledExecutorService scheduler;
|
private final ScheduledExecutorService scheduler;
|
||||||
private final Context appContext;
|
private final Context appContext;
|
||||||
private final LocationUtils locationUtils;
|
private final LocationUtils locationUtils;
|
||||||
private final DevReporter reporter;
|
|
||||||
private final SocketFactory torSocketFactory;
|
private final SocketFactory torSocketFactory;
|
||||||
|
private final Clock clock;
|
||||||
private final Backoff backoff;
|
private final Backoff backoff;
|
||||||
private final DuplexPluginCallback callback;
|
private final DuplexPluginCallback callback;
|
||||||
private final String architecture;
|
private final String architecture;
|
||||||
@@ -123,7 +123,7 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
|||||||
private final ConnectionStatus connectionStatus;
|
private final ConnectionStatus connectionStatus;
|
||||||
private final File torDirectory, torFile, geoIpFile, configFile;
|
private final File torDirectory, torFile, geoIpFile, configFile;
|
||||||
private final File doneFile, cookieFile;
|
private final File doneFile, cookieFile;
|
||||||
private final PowerManager.WakeLock wakeLock;
|
private final RenewableWakeLock wakeLock;
|
||||||
private final AtomicReference<Future<?>> connectivityCheck =
|
private final AtomicReference<Future<?>> connectivityCheck =
|
||||||
new AtomicReference<>();
|
new AtomicReference<>();
|
||||||
private final AtomicBoolean used = new AtomicBoolean(false);
|
private final AtomicBoolean used = new AtomicBoolean(false);
|
||||||
@@ -136,15 +136,15 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
|||||||
|
|
||||||
TorPlugin(Executor ioExecutor, ScheduledExecutorService scheduler,
|
TorPlugin(Executor ioExecutor, ScheduledExecutorService scheduler,
|
||||||
Context appContext, LocationUtils locationUtils,
|
Context appContext, LocationUtils locationUtils,
|
||||||
DevReporter reporter, SocketFactory torSocketFactory,
|
SocketFactory torSocketFactory, Clock clock, Backoff backoff,
|
||||||
Backoff backoff, DuplexPluginCallback callback,
|
DuplexPluginCallback callback, String architecture,
|
||||||
String architecture, int maxLatency, int maxIdleTime) {
|
int maxLatency, int maxIdleTime) {
|
||||||
this.ioExecutor = ioExecutor;
|
this.ioExecutor = ioExecutor;
|
||||||
this.scheduler = scheduler;
|
this.scheduler = scheduler;
|
||||||
this.appContext = appContext;
|
this.appContext = appContext;
|
||||||
this.locationUtils = locationUtils;
|
this.locationUtils = locationUtils;
|
||||||
this.reporter = reporter;
|
|
||||||
this.torSocketFactory = torSocketFactory;
|
this.torSocketFactory = torSocketFactory;
|
||||||
|
this.clock = clock;
|
||||||
this.backoff = backoff;
|
this.backoff = backoff;
|
||||||
this.callback = callback;
|
this.callback = callback;
|
||||||
this.architecture = architecture;
|
this.architecture = architecture;
|
||||||
@@ -160,14 +160,13 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
|||||||
configFile = new File(torDirectory, "torrc");
|
configFile = new File(torDirectory, "torrc");
|
||||||
doneFile = new File(torDirectory, "done");
|
doneFile = new File(torDirectory, "done");
|
||||||
cookieFile = new File(torDirectory, ".tor/control_auth_cookie");
|
cookieFile = new File(torDirectory, ".tor/control_auth_cookie");
|
||||||
Object o = appContext.getSystemService(POWER_SERVICE);
|
|
||||||
PowerManager pm = (PowerManager) o;
|
|
||||||
// This tag will prevent Huawei's powermanager from killing us.
|
|
||||||
wakeLock = pm.newWakeLock(PARTIAL_WAKE_LOCK, "LocationManagerService");
|
|
||||||
wakeLock.setReferenceCounted(false);
|
|
||||||
// Don't execute more than one connection status check at a time
|
// Don't execute more than one connection status check at a time
|
||||||
connectionStatusExecutor = new PoliteExecutor("TorPlugin",
|
connectionStatusExecutor = new PoliteExecutor("TorPlugin",
|
||||||
ioExecutor, 1);
|
ioExecutor, 1);
|
||||||
|
PowerManager pm = (PowerManager)
|
||||||
|
appContext.getSystemService(POWER_SERVICE);
|
||||||
|
wakeLock = new RenewableWakeLock(pm, scheduler, PARTIAL_WAKE_LOCK,
|
||||||
|
WAKE_LOCK_TAG, 1, MINUTES);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -190,18 +189,10 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
|||||||
if (used.getAndSet(true)) throw new IllegalStateException();
|
if (used.getAndSet(true)) throw new IllegalStateException();
|
||||||
// Install or update the assets if necessary
|
// Install or update the assets if necessary
|
||||||
if (!assetsAreUpToDate()) installAssets();
|
if (!assetsAreUpToDate()) installAssets();
|
||||||
LOG.info("Starting Tor");
|
if (cookieFile.exists() && !cookieFile.delete())
|
||||||
// Watch for the auth cookie file being updated
|
LOG.warning("Old auth cookie not deleted");
|
||||||
try {
|
|
||||||
cookieFile.getParentFile().mkdirs();
|
|
||||||
cookieFile.createNewFile();
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new PluginException(e);
|
|
||||||
}
|
|
||||||
CountDownLatch latch = new CountDownLatch(1);
|
|
||||||
FileObserver obs = new WriteObserver(cookieFile, latch);
|
|
||||||
obs.startWatching();
|
|
||||||
// Start a new Tor process
|
// Start a new Tor process
|
||||||
|
LOG.info("Starting Tor");
|
||||||
String torPath = torFile.getAbsolutePath();
|
String torPath = torFile.getAbsolutePath();
|
||||||
String configPath = configFile.getAbsolutePath();
|
String configPath = configFile.getAbsolutePath();
|
||||||
String pid = String.valueOf(android.os.Process.myPid());
|
String pid = String.valueOf(android.os.Process.myPid());
|
||||||
@@ -240,11 +231,16 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
|||||||
throw new PluginException();
|
throw new PluginException();
|
||||||
}
|
}
|
||||||
// Wait for the auth cookie file to be created/updated
|
// Wait for the auth cookie file to be created/updated
|
||||||
if (!latch.await(COOKIE_TIMEOUT, MILLISECONDS)) {
|
long start = clock.currentTimeMillis();
|
||||||
LOG.warning("Auth cookie not created");
|
while (cookieFile.length() < 32) {
|
||||||
if (LOG.isLoggable(INFO)) listFiles(torDirectory);
|
if (clock.currentTimeMillis() - start > COOKIE_TIMEOUT_MS) {
|
||||||
throw new PluginException();
|
LOG.warning("Auth cookie not created");
|
||||||
|
if (LOG.isLoggable(INFO)) listFiles(torDirectory);
|
||||||
|
throw new PluginException();
|
||||||
|
}
|
||||||
|
Thread.sleep(COOKIE_POLLING_INTERVAL_MS);
|
||||||
}
|
}
|
||||||
|
LOG.info("Auth cookie created");
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
LOG.warning("Interrupted while starting Tor");
|
LOG.warning("Interrupted while starting Tor");
|
||||||
Thread.currentThread().interrupt();
|
Thread.currentThread().interrupt();
|
||||||
@@ -338,7 +334,7 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
|||||||
return zin;
|
return zin;
|
||||||
}
|
}
|
||||||
|
|
||||||
private InputStream getConfigInputStream() throws IOException {
|
private InputStream getConfigInputStream() {
|
||||||
int resId = getResourceId("torrc");
|
int resId = getResourceId("torrc");
|
||||||
return appContext.getResources().openRawResource(resId);
|
return appContext.getResources().openRawResource(resId);
|
||||||
}
|
}
|
||||||
@@ -352,7 +348,7 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
|||||||
try {
|
try {
|
||||||
if (c != null) c.close();
|
if (c != null) c.close();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
logException(LOG, WARNING, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -360,7 +356,7 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
|||||||
try {
|
try {
|
||||||
if (s != null) s.close();
|
if (s != null) s.close();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
logException(LOG, WARNING, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -369,7 +365,7 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
|||||||
File[] children = f.listFiles();
|
File[] children = f.listFiles();
|
||||||
if (children != null) for (File child : children) listFiles(child);
|
if (children != null) for (File child : children) listFiles(child);
|
||||||
} else {
|
} else {
|
||||||
LOG.info(f.getAbsolutePath());
|
LOG.info(f.getAbsolutePath() + " " + f.length());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -389,14 +385,6 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void sendDevReports() {
|
|
||||||
ioExecutor.execute(() -> {
|
|
||||||
// TODO: Trigger this with a TransportEnabledEvent
|
|
||||||
File reportDir = AndroidUtils.getReportDir(appContext);
|
|
||||||
reporter.sendReports(reportDir);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void bind() {
|
private void bind() {
|
||||||
ioExecutor.execute(() -> {
|
ioExecutor.execute(() -> {
|
||||||
// If there's already a port number stored in config, reuse it
|
// If there's already a port number stored in config, reuse it
|
||||||
@@ -410,7 +398,7 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
|||||||
ss = new ServerSocket();
|
ss = new ServerSocket();
|
||||||
ss.bind(new InetSocketAddress("127.0.0.1", port));
|
ss.bind(new InetSocketAddress("127.0.0.1", port));
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
logException(LOG, WARNING, e);
|
||||||
tryToClose(ss);
|
tryToClose(ss);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -436,7 +424,7 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
|||||||
try {
|
try {
|
||||||
if (ss != null) ss.close();
|
if (ss != null) ss.close();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
logException(LOG, WARNING, e);
|
||||||
} finally {
|
} finally {
|
||||||
callback.transportDisabled();
|
callback.transportDisabled();
|
||||||
}
|
}
|
||||||
@@ -455,7 +443,7 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
|||||||
response = controlConnection.addOnion(portLines);
|
response = controlConnection.addOnion(portLines);
|
||||||
else response = controlConnection.addOnion(privKey, portLines);
|
else response = controlConnection.addOnion(privKey, portLines);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
logException(LOG, WARNING, e);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!response.containsKey(HS_ADDRESS)) {
|
if (!response.containsKey(HS_ADDRESS)) {
|
||||||
@@ -511,7 +499,7 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void stop() throws PluginException {
|
public void stop() {
|
||||||
running = false;
|
running = false;
|
||||||
tryToClose(socket);
|
tryToClose(socket);
|
||||||
if (networkStateReceiver != null)
|
if (networkStateReceiver != null)
|
||||||
@@ -523,7 +511,7 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
|||||||
controlConnection.shutdownTor("TERM");
|
controlConnection.shutdownTor("TERM");
|
||||||
controlSocket.close();
|
controlSocket.close();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
logException(LOG, WARNING, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
wakeLock.release();
|
wakeLock.release();
|
||||||
@@ -545,20 +533,16 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void poll(Collection<ContactId> connected) {
|
public void poll(Map<ContactId, TransportProperties> contacts) {
|
||||||
if (!isRunning()) return;
|
if (!isRunning()) return;
|
||||||
backoff.increment();
|
backoff.increment();
|
||||||
Map<ContactId, TransportProperties> remote =
|
for (Entry<ContactId, TransportProperties> e : contacts.entrySet()) {
|
||||||
callback.getRemoteProperties();
|
connectAndCallBack(e.getKey(), e.getValue());
|
||||||
for (Entry<ContactId, TransportProperties> e : remote.entrySet()) {
|
|
||||||
ContactId c = e.getKey();
|
|
||||||
if (!connected.contains(c)) connectAndCallBack(c, e.getValue());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void connectAndCallBack(ContactId c, TransportProperties p) {
|
private void connectAndCallBack(ContactId c, TransportProperties p) {
|
||||||
ioExecutor.execute(() -> {
|
ioExecutor.execute(() -> {
|
||||||
if (!isRunning()) return;
|
|
||||||
DuplexTransportConnection d = createConnection(p);
|
DuplexTransportConnection d = createConnection(p);
|
||||||
if (d != null) {
|
if (d != null) {
|
||||||
backoff.reset();
|
backoff.reset();
|
||||||
@@ -568,13 +552,8 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DuplexTransportConnection createConnection(ContactId c) {
|
public DuplexTransportConnection createConnection(TransportProperties p) {
|
||||||
if (!isRunning()) return null;
|
if (!isRunning()) return null;
|
||||||
return createConnection(callback.getRemoteProperties(c));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private DuplexTransportConnection createConnection(TransportProperties p) {
|
|
||||||
String onion = p.get(PROP_ONION);
|
String onion = p.get(PROP_ONION);
|
||||||
if (StringUtils.isNullOrEmpty(onion)) return null;
|
if (StringUtils.isNullOrEmpty(onion)) return null;
|
||||||
if (!ONION.matcher(onion).matches()) {
|
if (!ONION.matcher(onion).matches()) {
|
||||||
@@ -624,10 +603,7 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
|||||||
connectionStatus.getAndSetCircuitBuilt()) {
|
connectionStatus.getAndSetCircuitBuilt()) {
|
||||||
LOG.info("First circuit built");
|
LOG.info("First circuit built");
|
||||||
backoff.reset();
|
backoff.reset();
|
||||||
if (isRunning()) {
|
if (isRunning()) callback.transportEnabled();
|
||||||
sendDevReports();
|
|
||||||
callback.transportEnabled();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -656,10 +632,7 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
|||||||
if (severity.equals("NOTICE") && msg.startsWith("Bootstrapped 100%")) {
|
if (severity.equals("NOTICE") && msg.startsWith("Bootstrapped 100%")) {
|
||||||
connectionStatus.setBootstrapped();
|
connectionStatus.setBootstrapped();
|
||||||
backoff.reset();
|
backoff.reset();
|
||||||
if (isRunning()) {
|
if (isRunning()) callback.transportEnabled();
|
||||||
sendDevReports();
|
|
||||||
callback.transportEnabled();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -669,22 +642,6 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
|||||||
LOG.info("Descriptor uploaded");
|
LOG.info("Descriptor uploaded");
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class WriteObserver extends FileObserver {
|
|
||||||
|
|
||||||
private final CountDownLatch latch;
|
|
||||||
|
|
||||||
private WriteObserver(File file, CountDownLatch latch) {
|
|
||||||
super(file.getAbsolutePath(), CLOSE_WRITE);
|
|
||||||
this.latch = latch;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onEvent(int event, @Nullable String path) {
|
|
||||||
stopWatching();
|
|
||||||
latch.countDown();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void eventOccurred(Event e) {
|
public void eventOccurred(Event e) {
|
||||||
if (e instanceof SettingsUpdatedEvent) {
|
if (e instanceof SettingsUpdatedEvent) {
|
||||||
@@ -732,7 +689,7 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
|||||||
enableNetwork(true);
|
enableNetwork(true);
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
logException(LOG, WARNING, e);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import org.briarproject.bramble.api.plugin.TransportId;
|
|||||||
import org.briarproject.bramble.api.plugin.duplex.DuplexPlugin;
|
import org.briarproject.bramble.api.plugin.duplex.DuplexPlugin;
|
||||||
import org.briarproject.bramble.api.plugin.duplex.DuplexPluginCallback;
|
import org.briarproject.bramble.api.plugin.duplex.DuplexPluginCallback;
|
||||||
import org.briarproject.bramble.api.plugin.duplex.DuplexPluginFactory;
|
import org.briarproject.bramble.api.plugin.duplex.DuplexPluginFactory;
|
||||||
import org.briarproject.bramble.api.reporting.DevReporter;
|
import org.briarproject.bramble.api.system.Clock;
|
||||||
import org.briarproject.bramble.api.system.LocationUtils;
|
import org.briarproject.bramble.api.system.LocationUtils;
|
||||||
import org.briarproject.bramble.util.AndroidUtils;
|
import org.briarproject.bramble.util.AndroidUtils;
|
||||||
|
|
||||||
@@ -40,24 +40,24 @@ public class TorPluginFactory implements DuplexPluginFactory {
|
|||||||
private final ScheduledExecutorService scheduler;
|
private final ScheduledExecutorService scheduler;
|
||||||
private final Context appContext;
|
private final Context appContext;
|
||||||
private final LocationUtils locationUtils;
|
private final LocationUtils locationUtils;
|
||||||
private final DevReporter reporter;
|
|
||||||
private final EventBus eventBus;
|
private final EventBus eventBus;
|
||||||
private final SocketFactory torSocketFactory;
|
private final SocketFactory torSocketFactory;
|
||||||
private final BackoffFactory backoffFactory;
|
private final BackoffFactory backoffFactory;
|
||||||
|
private final Clock clock;
|
||||||
|
|
||||||
public TorPluginFactory(Executor ioExecutor,
|
public TorPluginFactory(Executor ioExecutor,
|
||||||
ScheduledExecutorService scheduler, Context appContext,
|
ScheduledExecutorService scheduler, Context appContext,
|
||||||
LocationUtils locationUtils, DevReporter reporter,
|
LocationUtils locationUtils, EventBus eventBus,
|
||||||
EventBus eventBus, SocketFactory torSocketFactory,
|
SocketFactory torSocketFactory, BackoffFactory backoffFactory,
|
||||||
BackoffFactory backoffFactory) {
|
Clock clock) {
|
||||||
this.ioExecutor = ioExecutor;
|
this.ioExecutor = ioExecutor;
|
||||||
this.scheduler = scheduler;
|
this.scheduler = scheduler;
|
||||||
this.appContext = appContext;
|
this.appContext = appContext;
|
||||||
this.locationUtils = locationUtils;
|
this.locationUtils = locationUtils;
|
||||||
this.reporter = reporter;
|
|
||||||
this.eventBus = eventBus;
|
this.eventBus = eventBus;
|
||||||
this.torSocketFactory = torSocketFactory;
|
this.torSocketFactory = torSocketFactory;
|
||||||
this.backoffFactory = backoffFactory;
|
this.backoffFactory = backoffFactory;
|
||||||
|
this.clock = clock;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -94,7 +94,7 @@ public class TorPluginFactory implements DuplexPluginFactory {
|
|||||||
Backoff backoff = backoffFactory.createBackoff(MIN_POLLING_INTERVAL,
|
Backoff backoff = backoffFactory.createBackoff(MIN_POLLING_INTERVAL,
|
||||||
MAX_POLLING_INTERVAL, BACKOFF_BASE);
|
MAX_POLLING_INTERVAL, BACKOFF_BASE);
|
||||||
TorPlugin plugin = new TorPlugin(ioExecutor, scheduler, appContext,
|
TorPlugin plugin = new TorPlugin(ioExecutor, scheduler, appContext,
|
||||||
locationUtils, reporter, torSocketFactory, backoff, callback,
|
locationUtils, torSocketFactory, clock, backoff, callback,
|
||||||
architecture, MAX_LATENCY, MAX_IDLE_TIME);
|
architecture, MAX_LATENCY, MAX_IDLE_TIME);
|
||||||
eventBus.addListener(plugin);
|
eventBus.addListener(plugin);
|
||||||
return plugin;
|
return plugin;
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import android.net.wifi.WifiConfiguration;
|
|||||||
import android.net.wifi.WifiManager;
|
import android.net.wifi.WifiManager;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Parcel;
|
import android.os.Parcel;
|
||||||
|
import android.os.StrictMode;
|
||||||
import android.provider.Settings;
|
import android.provider.Settings;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
@@ -66,9 +67,12 @@ class AndroidSecureRandomProvider extends LinuxSecureRandomProvider {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void writeSeed() {
|
protected void writeSeed() {
|
||||||
|
// Silence strict mode
|
||||||
|
StrictMode.ThreadPolicy tp = StrictMode.allowThreadDiskWrites();
|
||||||
super.writeSeed();
|
super.writeSeed();
|
||||||
if (Build.VERSION.SDK_INT >= 16 && Build.VERSION.SDK_INT <= 18)
|
if (Build.VERSION.SDK_INT >= 16 && Build.VERSION.SDK_INT <= 18)
|
||||||
applyOpenSslFix();
|
applyOpenSslFix();
|
||||||
|
StrictMode.setThreadPolicy(tp);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Based on https://android-developers.googleblog.com/2013/08/some-securerandom-thoughts.html
|
// Based on https://android-developers.googleblog.com/2013/08/some-securerandom-thoughts.html
|
||||||
|
|||||||
@@ -8,16 +8,13 @@ import android.os.Build;
|
|||||||
import android.provider.Settings;
|
import android.provider.Settings;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileNotFoundException;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Scanner;
|
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import static android.content.Context.MODE_PRIVATE;
|
import static android.content.Context.MODE_PRIVATE;
|
||||||
import static java.util.logging.Level.INFO;
|
|
||||||
|
|
||||||
public class AndroidUtils {
|
public class AndroidUtils {
|
||||||
|
|
||||||
@@ -61,77 +58,28 @@ public class AndroidUtils {
|
|||||||
&& !address.equals(FAKE_BLUETOOTH_ADDRESS);
|
&& !address.equals(FAKE_BLUETOOTH_ADDRESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void logDataDirContents(Context ctx) {
|
|
||||||
if (LOG.isLoggable(INFO)) {
|
|
||||||
LOG.info("Contents of data directory:");
|
|
||||||
logFileOrDir(new File(ctx.getApplicationInfo().dataDir));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void logFileOrDir(File f) {
|
|
||||||
LOG.info(f.getAbsolutePath() + " " + f.length());
|
|
||||||
if (f.isDirectory()) {
|
|
||||||
File[] children = f.listFiles();
|
|
||||||
if (children == null) {
|
|
||||||
LOG.info("Could not list files in " + f.getAbsolutePath());
|
|
||||||
} else {
|
|
||||||
for (File child : children) logFileOrDir(child);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static File getSharedPrefsFile(Context ctx, String name) {
|
|
||||||
File dataDir = new File(ctx.getApplicationInfo().dataDir);
|
|
||||||
File prefsDir = new File(dataDir, "shared_prefs");
|
|
||||||
return new File(prefsDir, name + ".xml");
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void logFileContents(File f) {
|
|
||||||
if (LOG.isLoggable(INFO)) {
|
|
||||||
LOG.info("Contents of " + f.getAbsolutePath() + ":");
|
|
||||||
try {
|
|
||||||
Scanner s = new Scanner(f);
|
|
||||||
while (s.hasNextLine()) LOG.info(s.nextLine());
|
|
||||||
s.close();
|
|
||||||
} catch (FileNotFoundException e) {
|
|
||||||
LOG.info(f.getAbsolutePath() + " not found");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressLint("ApplySharedPref")
|
|
||||||
public static void deleteAppData(Context ctx, SharedPreferences... clear) {
|
public static void deleteAppData(Context ctx, SharedPreferences... clear) {
|
||||||
// Clear and commit shared preferences
|
// Clear and commit shared preferences
|
||||||
for (SharedPreferences prefs : clear) {
|
for (SharedPreferences prefs : clear) {
|
||||||
boolean cleared = prefs.edit().clear().commit();
|
if (!prefs.edit().clear().commit())
|
||||||
if (LOG.isLoggable(INFO)) {
|
LOG.warning("Could not clear shared preferences");
|
||||||
if (cleared) LOG.info("Cleared shared preferences");
|
|
||||||
else LOG.info("Could not clear shared preferences");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// Delete files, except lib and shared_prefs directories
|
// Delete files, except lib and shared_prefs directories
|
||||||
File dataDir = new File(ctx.getApplicationInfo().dataDir);
|
File dataDir = new File(ctx.getApplicationInfo().dataDir);
|
||||||
if (LOG.isLoggable(INFO))
|
|
||||||
LOG.info("Deleting app data from " + dataDir.getAbsolutePath());
|
|
||||||
File[] children = dataDir.listFiles();
|
File[] children = dataDir.listFiles();
|
||||||
if (children != null) {
|
if (children == null) {
|
||||||
|
LOG.warning("Could not list files in app data dir");
|
||||||
|
} else {
|
||||||
for (File child : children) {
|
for (File child : children) {
|
||||||
String name = child.getName();
|
String name = child.getName();
|
||||||
if (!name.equals("lib") && !name.equals("shared_prefs")) {
|
if (!name.equals("lib") && !name.equals("shared_prefs")) {
|
||||||
if (LOG.isLoggable(INFO))
|
|
||||||
LOG.info("Deleting " + child.getAbsolutePath());
|
|
||||||
IoUtils.deleteFileOrDir(child);
|
IoUtils.deleteFileOrDir(child);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (LOG.isLoggable(INFO)) {
|
|
||||||
LOG.info("Could not list files in " + dataDir.getAbsolutePath());
|
|
||||||
}
|
}
|
||||||
// Recreate the cache dir as some OpenGL drivers expect it to exist
|
// Recreate the cache dir as some OpenGL drivers expect it to exist
|
||||||
boolean recreated = new File(dataDir, "cache").mkdir();
|
if (!new File(dataDir, "cache").mkdir())
|
||||||
if (LOG.isLoggable(INFO)) {
|
LOG.warning("Could not recreate cache dir");
|
||||||
if (recreated) LOG.info("Recreated cache dir");
|
|
||||||
else LOG.info("Could not recreate cache dir");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static File getReportDir(Context ctx) {
|
public static File getReportDir(Context ctx) {
|
||||||
|
|||||||
@@ -0,0 +1,100 @@
|
|||||||
|
package org.briarproject.bramble.util;
|
||||||
|
|
||||||
|
import android.os.PowerManager;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
|
||||||
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
|
import java.util.concurrent.ScheduledFuture;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import javax.annotation.concurrent.ThreadSafe;
|
||||||
|
|
||||||
|
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
||||||
|
import static java.util.logging.Level.INFO;
|
||||||
|
|
||||||
|
@ThreadSafe
|
||||||
|
@NotNullByDefault
|
||||||
|
public class RenewableWakeLock {
|
||||||
|
|
||||||
|
private static final Logger LOG =
|
||||||
|
Logger.getLogger(RenewableWakeLock.class.getName());
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Automatically release the lock this many milliseconds after it's due
|
||||||
|
* to have been replaced and released.
|
||||||
|
*/
|
||||||
|
private static final int SAFETY_MARGIN_MS = 10_000;
|
||||||
|
|
||||||
|
private final PowerManager powerManager;
|
||||||
|
private final ScheduledExecutorService scheduler;
|
||||||
|
private final int levelAndFlags;
|
||||||
|
private final String tag;
|
||||||
|
private final long durationMs;
|
||||||
|
private final Runnable renewTask;
|
||||||
|
|
||||||
|
private final Object lock = new Object();
|
||||||
|
@Nullable
|
||||||
|
private PowerManager.WakeLock wakeLock; // Locking: lock
|
||||||
|
@Nullable
|
||||||
|
private ScheduledFuture future; // Locking: lock
|
||||||
|
|
||||||
|
public RenewableWakeLock(PowerManager powerManager,
|
||||||
|
ScheduledExecutorService scheduler, int levelAndFlags, String tag,
|
||||||
|
long duration, TimeUnit timeUnit) {
|
||||||
|
this.powerManager = powerManager;
|
||||||
|
this.scheduler = scheduler;
|
||||||
|
this.levelAndFlags = levelAndFlags;
|
||||||
|
this.tag = tag;
|
||||||
|
durationMs = MILLISECONDS.convert(duration, timeUnit);
|
||||||
|
renewTask = this::renew;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void acquire() {
|
||||||
|
if (LOG.isLoggable(INFO)) LOG.info("Acquiring wake lock " + tag);
|
||||||
|
synchronized (lock) {
|
||||||
|
if (wakeLock != null) {
|
||||||
|
LOG.info("Already acquired");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
wakeLock = powerManager.newWakeLock(levelAndFlags, tag);
|
||||||
|
wakeLock.setReferenceCounted(false);
|
||||||
|
wakeLock.acquire(durationMs + SAFETY_MARGIN_MS);
|
||||||
|
future = scheduler.schedule(renewTask, durationMs, MILLISECONDS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void renew() {
|
||||||
|
if (LOG.isLoggable(INFO)) LOG.info("Renewing wake lock " + tag);
|
||||||
|
synchronized (lock) {
|
||||||
|
if (wakeLock == null) {
|
||||||
|
LOG.info("Already released");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
PowerManager.WakeLock oldWakeLock = wakeLock;
|
||||||
|
wakeLock = powerManager.newWakeLock(levelAndFlags, tag);
|
||||||
|
wakeLock.setReferenceCounted(false);
|
||||||
|
wakeLock.acquire(durationMs + SAFETY_MARGIN_MS);
|
||||||
|
oldWakeLock.release();
|
||||||
|
future = scheduler.schedule(renewTask, durationMs, MILLISECONDS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void release() {
|
||||||
|
if (LOG.isLoggable(INFO)) LOG.info("Releasing wake lock " + tag);
|
||||||
|
synchronized (lock) {
|
||||||
|
if (wakeLock == null) {
|
||||||
|
LOG.info("Already released");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (future == null) throw new AssertionError();
|
||||||
|
future.cancel(false);
|
||||||
|
future = null;
|
||||||
|
wakeLock.release();
|
||||||
|
wakeLock = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -2,6 +2,7 @@ apply plugin: 'java-library'
|
|||||||
sourceCompatibility = 1.8
|
sourceCompatibility = 1.8
|
||||||
targetCompatibility = 1.8
|
targetCompatibility = 1.8
|
||||||
|
|
||||||
|
apply plugin: 'ru.vyarus.animalsniffer'
|
||||||
apply plugin: 'witness'
|
apply plugin: 'witness'
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
@@ -14,6 +15,8 @@ dependencies {
|
|||||||
testImplementation "org.jmock:jmock-legacy:2.8.2"
|
testImplementation "org.jmock:jmock-legacy:2.8.2"
|
||||||
testImplementation "org.hamcrest:hamcrest-library:1.3"
|
testImplementation "org.hamcrest:hamcrest-library:1.3"
|
||||||
testImplementation "org.hamcrest:hamcrest-core:1.3"
|
testImplementation "org.hamcrest:hamcrest-core:1.3"
|
||||||
|
|
||||||
|
signature 'org.codehaus.mojo.signature:java16:1.1@signature'
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencyVerification {
|
dependencyVerification {
|
||||||
@@ -26,6 +29,9 @@ dependencyVerification {
|
|||||||
'org.apache.ant:ant-launcher:1.9.4:ant-launcher-1.9.4.jar:7bccea20b41801ca17bcbc909a78c835d0f443f12d639c77bd6ae3d05861608d',
|
'org.apache.ant:ant-launcher:1.9.4:ant-launcher-1.9.4.jar:7bccea20b41801ca17bcbc909a78c835d0f443f12d639c77bd6ae3d05861608d',
|
||||||
'org.apache.ant:ant:1.9.4:ant-1.9.4.jar:649ae0730251de07b8913f49286d46bba7b92d47c5f332610aa426c4f02161d8',
|
'org.apache.ant:ant:1.9.4:ant-1.9.4.jar:649ae0730251de07b8913f49286d46bba7b92d47c5f332610aa426c4f02161d8',
|
||||||
'org.beanshell:bsh:1.3.0:bsh-1.3.0.jar:9b04edc75d19db54f1b4e8b5355e9364384c6cf71eb0a1b9724c159d779879f8',
|
'org.beanshell:bsh:1.3.0:bsh-1.3.0.jar:9b04edc75d19db54f1b4e8b5355e9364384c6cf71eb0a1b9724c159d779879f8',
|
||||||
|
'org.codehaus.mojo.signature:java16:1.1:java16-1.1.signature:53799223a2c98dba2d0add810bed76315460df285c69e4f397ae6098f87dd619',
|
||||||
|
'org.codehaus.mojo:animal-sniffer-ant-tasks:1.16:animal-sniffer-ant-tasks-1.16.jar:890040976fbe2d584619a6a61b1fd2e925b3b5eb342a85eb2762c467c0d64e90',
|
||||||
|
'org.codehaus.mojo:animal-sniffer:1.16:animal-sniffer-1.16.jar:72be8bcc226ba43b937c722a08a07852bfa1b11400089265d5df0ee7b38b1d52',
|
||||||
'org.hamcrest:hamcrest-core:1.3:hamcrest-core-1.3.jar:66fdef91e9739348df7a096aa384a5685f4e875584cce89386a7a47251c4d8e9',
|
'org.hamcrest:hamcrest-core:1.3:hamcrest-core-1.3.jar:66fdef91e9739348df7a096aa384a5685f4e875584cce89386a7a47251c4d8e9',
|
||||||
'org.hamcrest:hamcrest-library:1.3:hamcrest-library-1.3.jar:711d64522f9ec410983bd310934296da134be4254a125080a0416ec178dfad1c',
|
'org.hamcrest:hamcrest-library:1.3:hamcrest-library-1.3.jar:711d64522f9ec410983bd310934296da134be4254a125080a0416ec178dfad1c',
|
||||||
'org.jmock:jmock-junit4:2.8.2:jmock-junit4-2.8.2.jar:f7ee4df4f7bd7b7f1cafad3b99eb74d579f109d5992ff625347352edb55e674c',
|
'org.jmock:jmock-junit4:2.8.2:jmock-junit4-2.8.2.jar:f7ee4df4f7bd7b7f1cafad3b99eb74d579f109d5992ff625347352edb55e674c',
|
||||||
@@ -33,6 +39,7 @@ dependencyVerification {
|
|||||||
'org.jmock:jmock-testjar:2.8.2:jmock-testjar-2.8.2.jar:8900860f72c474e027cf97fe78dcbf154a1aa7fc62b6845c5fb4e4f3c7bc8760',
|
'org.jmock:jmock-testjar:2.8.2:jmock-testjar-2.8.2.jar:8900860f72c474e027cf97fe78dcbf154a1aa7fc62b6845c5fb4e4f3c7bc8760',
|
||||||
'org.jmock:jmock:2.8.2:jmock-2.8.2.jar:6c73cb4a2e6dbfb61fd99c9a768539c170ab6568e57846bd60dbf19596b65b16',
|
'org.jmock:jmock:2.8.2:jmock-2.8.2.jar:6c73cb4a2e6dbfb61fd99c9a768539c170ab6568e57846bd60dbf19596b65b16',
|
||||||
'org.objenesis:objenesis:2.1:objenesis-2.1.jar:c74330cc6b806c804fd37e74487b4fe5d7c2750c5e15fbc6efa13bdee1bdef80',
|
'org.objenesis:objenesis:2.1:objenesis-2.1.jar:c74330cc6b806c804fd37e74487b4fe5d7c2750c5e15fbc6efa13bdee1bdef80',
|
||||||
|
'org.ow2.asm:asm-all:5.2:asm-all-5.2.jar:7fbffbc1db3422e2101689fd88df8384b15817b52b9b2b267b9f6d2511dc198d',
|
||||||
'org.ow2.asm:asm:5.0.4:asm-5.0.4.jar:896618ed8ae62702521a78bc7be42b7c491a08e6920a15f89a3ecdec31e9a220',
|
'org.ow2.asm:asm:5.0.4:asm-5.0.4.jar:896618ed8ae62702521a78bc7be42b7c491a08e6920a15f89a3ecdec31e9a220',
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -48,8 +55,3 @@ task jarTest(type: Jar, dependsOn: testClasses) {
|
|||||||
artifacts {
|
artifacts {
|
||||||
testOutput jarTest
|
testOutput jarTest
|
||||||
}
|
}
|
||||||
|
|
||||||
// If a Java 6 JRE is available, check we're not using any Java 7 or 8 APIs
|
|
||||||
tasks.withType(JavaCompile) {
|
|
||||||
useJava6StandardLibrary(it)
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -45,9 +45,9 @@ public interface ContactManager {
|
|||||||
*
|
*
|
||||||
* @param alice true if the local party is Alice
|
* @param alice true if the local party is Alice
|
||||||
*/
|
*/
|
||||||
ContactId addContact(Author remote, AuthorId local,
|
ContactId addContact(Author remote, AuthorId local, SecretKey master,
|
||||||
SecretKey master, long timestamp, boolean alice, boolean verified,
|
long timestamp, boolean alice, boolean verified, boolean active)
|
||||||
boolean active) throws DbException;
|
throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the contact with the given ID.
|
* Returns the contact with the given ID.
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import java.io.IOException;
|
|||||||
public interface BdfReader {
|
public interface BdfReader {
|
||||||
|
|
||||||
int DEFAULT_NESTED_LIMIT = 5;
|
int DEFAULT_NESTED_LIMIT = 5;
|
||||||
|
int DEFAULT_MAX_BUFFER_SIZE = 64 * 1024;
|
||||||
|
|
||||||
boolean eof() throws IOException;
|
boolean eof() throws IOException;
|
||||||
|
|
||||||
@@ -39,13 +40,13 @@ public interface BdfReader {
|
|||||||
|
|
||||||
boolean hasString() throws IOException;
|
boolean hasString() throws IOException;
|
||||||
|
|
||||||
String readString(int maxLength) throws IOException;
|
String readString() throws IOException;
|
||||||
|
|
||||||
void skipString() throws IOException;
|
void skipString() throws IOException;
|
||||||
|
|
||||||
boolean hasRaw() throws IOException;
|
boolean hasRaw() throws IOException;
|
||||||
|
|
||||||
byte[] readRaw(int maxLength) throws IOException;
|
byte[] readRaw() throws IOException;
|
||||||
|
|
||||||
void skipRaw() throws IOException;
|
void skipRaw() throws IOException;
|
||||||
|
|
||||||
|
|||||||
@@ -9,5 +9,6 @@ public interface BdfReaderFactory {
|
|||||||
|
|
||||||
BdfReader createReader(InputStream in);
|
BdfReader createReader(InputStream in);
|
||||||
|
|
||||||
BdfReader createReader(InputStream in, int nestedLimit);
|
BdfReader createReader(InputStream in, int nestedLimit,
|
||||||
|
int maxBufferSize);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -104,18 +104,12 @@ public interface DatabaseComponent {
|
|||||||
throws DbException;
|
throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stores the given transport keys, optionally binding them to the given
|
* Stores the given transport keys for the given contact and returns a
|
||||||
* contact, and returns a key set ID.
|
* key set ID.
|
||||||
*/
|
*/
|
||||||
KeySetId addTransportKeys(Transaction txn, @Nullable ContactId c,
|
KeySetId addTransportKeys(Transaction txn, ContactId c,
|
||||||
TransportKeys k) throws DbException;
|
TransportKeys k) throws DbException;
|
||||||
|
|
||||||
/**
|
|
||||||
* Binds the given keys for the given transport to the given contact.
|
|
||||||
*/
|
|
||||||
void bindTransportKeys(Transaction txn, ContactId c, TransportId t,
|
|
||||||
KeySetId k) throws DbException;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if the database contains the given contact for the given
|
* Returns true if the database contains the given contact for the given
|
||||||
* local pseudonym.
|
* local pseudonym.
|
||||||
|
|||||||
@@ -14,6 +14,8 @@ public interface DatabaseConfig {
|
|||||||
|
|
||||||
File getDatabaseDirectory();
|
File getDatabaseDirectory();
|
||||||
|
|
||||||
|
File getDatabaseKeyDirectory();
|
||||||
|
|
||||||
void setEncryptionKey(SecretKey key);
|
void setEncryptionKey(SecretKey key);
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
package org.briarproject.bramble.api.plugin;
|
||||||
|
|
||||||
|
public interface FileConstants {
|
||||||
|
|
||||||
|
String PROP_PATH = "path";
|
||||||
|
}
|
||||||
@@ -2,8 +2,9 @@ package org.briarproject.bramble.api.plugin;
|
|||||||
|
|
||||||
import org.briarproject.bramble.api.contact.ContactId;
|
import org.briarproject.bramble.api.contact.ContactId;
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
import org.briarproject.bramble.api.properties.TransportProperties;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Map;
|
||||||
|
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
public interface Plugin {
|
public interface Plugin {
|
||||||
@@ -39,21 +40,19 @@ public interface Plugin {
|
|||||||
boolean isRunning();
|
boolean isRunning();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if the plugin's {@link #poll(Collection)} method should be
|
* Returns true if the plugin should be polled periodically to attempt to
|
||||||
* called periodically to attempt to establish connections.
|
* establish connections.
|
||||||
*/
|
*/
|
||||||
boolean shouldPoll();
|
boolean shouldPoll();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the desired interval in milliseconds between calls to the
|
* Returns the desired interval in milliseconds between polling attempts.
|
||||||
* plugin's {@link #poll(Collection)} method.
|
|
||||||
*/
|
*/
|
||||||
int getPollingInterval();
|
int getPollingInterval();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attempts to establish connections to contacts, passing any created
|
* Attempts to establish connections to the given contacts, passing any
|
||||||
* connections to the callback. To avoid creating redundant connections,
|
* created connections to the callback.
|
||||||
* the plugin may exclude the given contacts from polling.
|
|
||||||
*/
|
*/
|
||||||
void poll(Collection<ContactId> connected);
|
void poll(Map<ContactId, TransportProperties> contacts);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,9 @@
|
|||||||
package org.briarproject.bramble.api.plugin;
|
package org.briarproject.bramble.api.plugin;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.contact.ContactId;
|
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
import org.briarproject.bramble.api.properties.TransportProperties;
|
import org.briarproject.bramble.api.properties.TransportProperties;
|
||||||
import org.briarproject.bramble.api.settings.Settings;
|
import org.briarproject.bramble.api.settings.Settings;
|
||||||
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An interface through which a transport plugin interacts with the rest of
|
* An interface through which a transport plugin interacts with the rest of
|
||||||
* the application.
|
* the application.
|
||||||
@@ -25,17 +22,7 @@ public interface PluginCallback {
|
|||||||
TransportProperties getLocalProperties();
|
TransportProperties getLocalProperties();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the plugin's remote transport properties.
|
* Merges the given settings with the plugin's settings
|
||||||
*/
|
|
||||||
Map<ContactId, TransportProperties> getRemoteProperties();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the plugin's remote transport properties for the given contact.
|
|
||||||
*/
|
|
||||||
TransportProperties getRemoteProperties(ContactId c);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Merges the given settings with the namespaced settings
|
|
||||||
*/
|
*/
|
||||||
void mergeSettings(Settings s);
|
void mergeSettings(Settings s);
|
||||||
|
|
||||||
@@ -45,34 +32,12 @@ public interface PluginCallback {
|
|||||||
void mergeLocalProperties(TransportProperties p);
|
void mergeLocalProperties(TransportProperties p);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Presents the user with a choice among two or more named options and
|
* Signals that the transport is enabled.
|
||||||
* returns the user's response. The message may consist of a translatable
|
|
||||||
* format string and arguments.
|
|
||||||
*
|
|
||||||
* @return an index into the array of options indicating the user's choice,
|
|
||||||
* or -1 if the user cancelled the choice.
|
|
||||||
*/
|
|
||||||
int showChoice(String[] options, String... message);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Asks the user to confirm an action and returns the user's response. The
|
|
||||||
* message may consist of a translatable format string and arguments.
|
|
||||||
*/
|
|
||||||
boolean showConfirmationMessage(String... message);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Shows a message to the user. The message may consist of a translatable
|
|
||||||
* format string and arguments.
|
|
||||||
*/
|
|
||||||
void showMessage(String... message);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Signal that the transport got enabled.
|
|
||||||
*/
|
*/
|
||||||
void transportEnabled();
|
void transportEnabled();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Signal that the transport got disabled.
|
* Signals that the transport is disabled.
|
||||||
*/
|
*/
|
||||||
void transportDisabled();
|
void transportDisabled();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,4 +12,6 @@ public interface PluginConfig {
|
|||||||
Collection<DuplexPluginFactory> getDuplexFactories();
|
Collection<DuplexPluginFactory> getDuplexFactories();
|
||||||
|
|
||||||
Collection<SimplexPluginFactory> getSimplexFactories();
|
Collection<SimplexPluginFactory> getSimplexFactories();
|
||||||
|
|
||||||
|
boolean shouldPoll();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,11 +22,6 @@ public interface TransportConnectionWriter {
|
|||||||
*/
|
*/
|
||||||
int getMaxIdleTime();
|
int getMaxIdleTime();
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the capacity of the transport connection in bytes.
|
|
||||||
*/
|
|
||||||
long getCapacity();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns an output stream for writing to the transport connection.
|
* Returns an output stream for writing to the transport connection.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -71,11 +71,6 @@ public abstract class AbstractDuplexTransportConnection
|
|||||||
return plugin.getMaxIdleTime();
|
return plugin.getMaxIdleTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public long getCapacity() {
|
|
||||||
return Long.MAX_VALUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public OutputStream getOutputStream() throws IOException {
|
public OutputStream getOutputStream() throws IOException {
|
||||||
return AbstractDuplexTransportConnection.this.getOutputStream();
|
return AbstractDuplexTransportConnection.this.getOutputStream();
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
package org.briarproject.bramble.api.plugin.duplex;
|
package org.briarproject.bramble.api.plugin.duplex;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.contact.ContactId;
|
|
||||||
import org.briarproject.bramble.api.data.BdfList;
|
import org.briarproject.bramble.api.data.BdfList;
|
||||||
import org.briarproject.bramble.api.keyagreement.KeyAgreementListener;
|
import org.briarproject.bramble.api.keyagreement.KeyAgreementListener;
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
import org.briarproject.bramble.api.plugin.Plugin;
|
import org.briarproject.bramble.api.plugin.Plugin;
|
||||||
|
import org.briarproject.bramble.api.properties.TransportProperties;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
@@ -15,12 +15,11 @@ import javax.annotation.Nullable;
|
|||||||
public interface DuplexPlugin extends Plugin {
|
public interface DuplexPlugin extends Plugin {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attempts to create and return a connection to the given contact using
|
* Attempts to create and return a connection using the given transport
|
||||||
* the current transport and configuration properties. Returns null if a
|
* properties. Returns null if a connection cannot be created.
|
||||||
* connection cannot be created.
|
|
||||||
*/
|
*/
|
||||||
@Nullable
|
@Nullable
|
||||||
DuplexTransportConnection createConnection(ContactId c);
|
DuplexTransportConnection createConnection(TransportProperties p);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if the plugin supports short-range key agreement.
|
* Returns true if the plugin supports short-range key agreement.
|
||||||
|
|||||||
@@ -5,7 +5,8 @@ import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
|||||||
import org.briarproject.bramble.api.plugin.PluginCallback;
|
import org.briarproject.bramble.api.plugin.PluginCallback;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An interface for handling connections created by a duplex transport plugin.
|
* An interface through which a duplex plugin interacts with the rest of the
|
||||||
|
* application.
|
||||||
*/
|
*/
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
public interface DuplexPluginCallback extends PluginCallback {
|
public interface DuplexPluginCallback extends PluginCallback {
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
package org.briarproject.bramble.api.plugin.simplex;
|
package org.briarproject.bramble.api.plugin.simplex;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.contact.ContactId;
|
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
import org.briarproject.bramble.api.plugin.Plugin;
|
import org.briarproject.bramble.api.plugin.Plugin;
|
||||||
import org.briarproject.bramble.api.plugin.TransportConnectionReader;
|
import org.briarproject.bramble.api.plugin.TransportConnectionReader;
|
||||||
import org.briarproject.bramble.api.plugin.TransportConnectionWriter;
|
import org.briarproject.bramble.api.plugin.TransportConnectionWriter;
|
||||||
|
import org.briarproject.bramble.api.properties.TransportProperties;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
@@ -15,18 +15,16 @@ import javax.annotation.Nullable;
|
|||||||
public interface SimplexPlugin extends Plugin {
|
public interface SimplexPlugin extends Plugin {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attempts to create and return a reader for the given contact using the
|
* Attempts to create and return a reader for the given transport
|
||||||
* current transport and configuration properties. Returns null if a reader
|
* properties. Returns null if a reader cannot be created.
|
||||||
* cannot be created.
|
|
||||||
*/
|
*/
|
||||||
@Nullable
|
@Nullable
|
||||||
TransportConnectionReader createReader(ContactId c);
|
TransportConnectionReader createReader(TransportProperties p);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attempts to create and return a writer for the given contact using the
|
* Attempts to create and return a writer for the given transport
|
||||||
* current transport and configuration properties. Returns null if a writer
|
* properties. Returns null if a writer cannot be created.
|
||||||
* cannot be created.
|
|
||||||
*/
|
*/
|
||||||
@Nullable
|
@Nullable
|
||||||
TransportConnectionWriter createWriter(ContactId c);
|
TransportConnectionWriter createWriter(TransportProperties p);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ import org.briarproject.bramble.api.plugin.TransportConnectionReader;
|
|||||||
import org.briarproject.bramble.api.plugin.TransportConnectionWriter;
|
import org.briarproject.bramble.api.plugin.TransportConnectionWriter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An interface for handling readers and writers created by a simplex transport
|
* An interface through which a simplex plugin interacts with the rest of the
|
||||||
* plugin.
|
* application.
|
||||||
*/
|
*/
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
public interface SimplexPluginCallback extends PluginCallback {
|
public interface SimplexPluginCallback extends PluginCallback {
|
||||||
|
|||||||
@@ -3,10 +3,14 @@ package org.briarproject.bramble.api.reporting;
|
|||||||
import org.briarproject.bramble.api.crypto.PublicKey;
|
import org.briarproject.bramble.api.crypto.PublicKey;
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
public interface DevConfig {
|
public interface DevConfig {
|
||||||
|
|
||||||
PublicKey getDevPublicKey();
|
PublicKey getDevPublicKey();
|
||||||
|
|
||||||
String getDevOnionAddress();
|
String getDevOnionAddress();
|
||||||
|
|
||||||
|
File getReportDir();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,8 +23,6 @@ public interface DevReporter {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Sends any reports previously stored on disk.
|
* Sends any reports previously stored on disk.
|
||||||
*
|
|
||||||
* @param reportDir the directory where reports are stored.
|
|
||||||
*/
|
*/
|
||||||
void sendReports(File reportDir);
|
void sendReports();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,48 +19,24 @@ public interface KeyManager {
|
|||||||
/**
|
/**
|
||||||
* Informs the key manager that a new contact has been added. Derives and
|
* Informs the key manager that a new contact has been added. Derives and
|
||||||
* stores a set of transport keys for communicating with the contact over
|
* stores a set of transport keys for communicating with the contact over
|
||||||
* each transport.
|
* each transport and returns the key set IDs.
|
||||||
* <p/>
|
* <p/>
|
||||||
* {@link StreamContext StreamContexts} for the contact can be created
|
* {@link StreamContext StreamContexts} for the contact can be created
|
||||||
* after this method has returned.
|
* after this method has returned.
|
||||||
*
|
*
|
||||||
* @param alice true if the local party is Alice
|
* @param alice true if the local party is Alice
|
||||||
|
* @param active whether the derived keys can be used for outgoing streams
|
||||||
*/
|
*/
|
||||||
void addContact(Transaction txn, ContactId c, SecretKey master,
|
Map<TransportId, KeySetId> addContact(Transaction txn, ContactId c,
|
||||||
long timestamp, boolean alice) throws DbException;
|
SecretKey master, long timestamp, boolean alice, boolean active)
|
||||||
|
|
||||||
/**
|
|
||||||
* Derives and stores a set of unbound transport keys for each transport
|
|
||||||
* and returns the key set IDs.
|
|
||||||
* <p/>
|
|
||||||
* The keys must be bound before they can be used for incoming streams,
|
|
||||||
* and also activated before they can be used for outgoing streams.
|
|
||||||
*
|
|
||||||
* @param alice true if the local party is Alice
|
|
||||||
*/
|
|
||||||
Map<TransportId, KeySetId> addUnboundKeys(Transaction txn, SecretKey master,
|
|
||||||
long timestamp, boolean alice) throws DbException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Binds the given transport keys to the given contact.
|
|
||||||
*/
|
|
||||||
void bindKeys(Transaction txn, ContactId c, Map<TransportId, KeySetId> keys)
|
|
||||||
throws DbException;
|
throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Marks the given transport keys as usable for outgoing streams. Keys must
|
* Marks the given transport keys as usable for outgoing streams.
|
||||||
* be bound before they are activated.
|
|
||||||
*/
|
*/
|
||||||
void activateKeys(Transaction txn, Map<TransportId, KeySetId> keys)
|
void activateKeys(Transaction txn, Map<TransportId, KeySetId> keys)
|
||||||
throws DbException;
|
throws DbException;
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes the given transport keys, which must not have been bound, from
|
|
||||||
* the manager and the database.
|
|
||||||
*/
|
|
||||||
void removeKeys(Transaction txn, Map<TransportId, KeySetId> keys)
|
|
||||||
throws DbException;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if we have keys that can be used for outgoing streams to
|
* Returns true if we have keys that can be used for outgoing streams to
|
||||||
* the given contact over the given transport.
|
* the given contact over the given transport.
|
||||||
|
|||||||
@@ -3,23 +3,20 @@ package org.briarproject.bramble.api.transport;
|
|||||||
import org.briarproject.bramble.api.contact.ContactId;
|
import org.briarproject.bramble.api.contact.ContactId;
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
import javax.annotation.concurrent.Immutable;
|
import javax.annotation.concurrent.Immutable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A set of transport keys for communicating with a contact. If the keys have
|
* A set of transport keys for communicating with a contact.
|
||||||
* not yet been bound to a contact, {@link #getContactId()}} returns null.
|
|
||||||
*/
|
*/
|
||||||
@Immutable
|
@Immutable
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
public class KeySet {
|
public class KeySet {
|
||||||
|
|
||||||
private final KeySetId keySetId;
|
private final KeySetId keySetId;
|
||||||
@Nullable
|
|
||||||
private final ContactId contactId;
|
private final ContactId contactId;
|
||||||
private final TransportKeys transportKeys;
|
private final TransportKeys transportKeys;
|
||||||
|
|
||||||
public KeySet(KeySetId keySetId, @Nullable ContactId contactId,
|
public KeySet(KeySetId keySetId, ContactId contactId,
|
||||||
TransportKeys transportKeys) {
|
TransportKeys transportKeys) {
|
||||||
this.keySetId = keySetId;
|
this.keySetId = keySetId;
|
||||||
this.contactId = contactId;
|
this.contactId = contactId;
|
||||||
@@ -30,7 +27,6 @@ public class KeySet {
|
|||||||
return keySetId;
|
return keySetId;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
|
||||||
public ContactId getContactId() {
|
public ContactId getContactId() {
|
||||||
return contactId;
|
return contactId;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,26 +0,0 @@
|
|||||||
package org.briarproject.bramble.api.ui;
|
|
||||||
|
|
||||||
public interface UiCallback {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Presents the user with a choice among two or more named options and
|
|
||||||
* returns the user's response. The message may consist of a translatable
|
|
||||||
* format string and arguments.
|
|
||||||
*
|
|
||||||
* @return an index into the array of options indicating the user's choice,
|
|
||||||
* or -1 if the user cancelled the choice.
|
|
||||||
*/
|
|
||||||
int showChoice(String[] options, String... message);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Asks the user to confirm an action and returns the user's response. The
|
|
||||||
* message may consist of a translatable format string and arguments.
|
|
||||||
*/
|
|
||||||
boolean showConfirmationMessage(String... message);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Shows a message to the user. The message may consist of a translatable
|
|
||||||
* format string and arguments.
|
|
||||||
*/
|
|
||||||
void showMessage(String... message);
|
|
||||||
}
|
|
||||||
@@ -13,7 +13,7 @@ import java.util.logging.Logger;
|
|||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
import static java.util.logging.Level.INFO;
|
import static java.util.logging.Level.WARNING;
|
||||||
|
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
public class IoUtils {
|
public class IoUtils {
|
||||||
@@ -25,18 +25,21 @@ public class IoUtils {
|
|||||||
delete(f);
|
delete(f);
|
||||||
} else if (f.isDirectory()) {
|
} else if (f.isDirectory()) {
|
||||||
File[] children = f.listFiles();
|
File[] children = f.listFiles();
|
||||||
if (children != null)
|
if (children == null) {
|
||||||
|
if (LOG.isLoggable(WARNING)) {
|
||||||
|
LOG.warning("Could not list files in "
|
||||||
|
+ f.getAbsolutePath());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
for (File child : children) deleteFileOrDir(child);
|
for (File child : children) deleteFileOrDir(child);
|
||||||
|
}
|
||||||
delete(f);
|
delete(f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void delete(File f) {
|
private static void delete(File f) {
|
||||||
boolean deleted = f.delete();
|
if (!f.delete() && LOG.isLoggable(WARNING))
|
||||||
if (LOG.isLoggable(INFO)) {
|
LOG.warning("Could not delete " + f.getAbsolutePath());
|
||||||
if (deleted) LOG.info("Deleted " + f.getAbsolutePath());
|
|
||||||
else LOG.info("Could not delete " + f.getAbsolutePath());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void copyAndClose(InputStream in, OutputStream out) {
|
public static void copyAndClose(InputStream in, OutputStream out) {
|
||||||
|
|||||||
@@ -0,0 +1,36 @@
|
|||||||
|
package org.briarproject.bramble.util;
|
||||||
|
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import static java.util.logging.Level.FINE;
|
||||||
|
|
||||||
|
public class LogUtils {
|
||||||
|
|
||||||
|
private static final int NANOS_PER_MILLI = 1000 * 1000;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the elapsed time in milliseconds since some arbitrary
|
||||||
|
* starting time. This is only useful for measuring elapsed time.
|
||||||
|
*/
|
||||||
|
public static long now() {
|
||||||
|
return System.nanoTime() / NANOS_PER_MILLI;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Logs the duration of a task.
|
||||||
|
* @param logger the logger to use
|
||||||
|
* @param task a description of the task
|
||||||
|
* @param start the start time of the task, as returned by {@link #now()}
|
||||||
|
*/
|
||||||
|
public static void logDuration(Logger logger, String task, long start) {
|
||||||
|
if (logger.isLoggable(FINE)) {
|
||||||
|
long duration = now() - start;
|
||||||
|
logger.fine(task + " took " + duration + " ms");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void logException(Logger logger, Level level, Throwable t) {
|
||||||
|
if (logger.isLoggable(level)) logger.log(level, t.toString(), t);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -22,19 +22,6 @@ public class OsUtils {
|
|||||||
return os != null && os.contains("Mac OS");
|
return os != null && os.contains("Mac OS");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isMacLeopardOrNewer() {
|
|
||||||
if (!isMac() || version == null) return false;
|
|
||||||
try {
|
|
||||||
String[] v = version.split("\\.");
|
|
||||||
if (v.length != 3) return false;
|
|
||||||
int major = Integer.parseInt(v[0]);
|
|
||||||
int minor = Integer.parseInt(v[1]);
|
|
||||||
return major >= 10 && minor >= 5;
|
|
||||||
} catch (NumberFormatException e) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean isLinux() {
|
public static boolean isLinux() {
|
||||||
return os != null && os.contains("Linux") && !isAndroid();
|
return os != null && os.contains("Linux") && !isAndroid();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ apply plugin: 'java-library'
|
|||||||
sourceCompatibility = 1.8
|
sourceCompatibility = 1.8
|
||||||
targetCompatibility = 1.8
|
targetCompatibility = 1.8
|
||||||
|
|
||||||
|
apply plugin: 'ru.vyarus.animalsniffer'
|
||||||
apply plugin: 'net.ltgt.apt'
|
apply plugin: 'net.ltgt.apt'
|
||||||
apply plugin: 'idea'
|
apply plugin: 'idea'
|
||||||
apply plugin: 'witness'
|
apply plugin: 'witness'
|
||||||
@@ -26,6 +27,8 @@ dependencies {
|
|||||||
testImplementation "org.hamcrest:hamcrest-core:1.3"
|
testImplementation "org.hamcrest:hamcrest-core:1.3"
|
||||||
|
|
||||||
testApt 'com.google.dagger:dagger-compiler:2.0.2'
|
testApt 'com.google.dagger:dagger-compiler:2.0.2'
|
||||||
|
|
||||||
|
signature 'org.codehaus.mojo.signature:java16:1.1@signature'
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencyVerification {
|
dependencyVerification {
|
||||||
@@ -44,6 +47,9 @@ dependencyVerification {
|
|||||||
'org.apache.ant:ant:1.9.4:ant-1.9.4.jar:649ae0730251de07b8913f49286d46bba7b92d47c5f332610aa426c4f02161d8',
|
'org.apache.ant:ant:1.9.4:ant-1.9.4.jar:649ae0730251de07b8913f49286d46bba7b92d47c5f332610aa426c4f02161d8',
|
||||||
'org.beanshell:bsh:1.3.0:bsh-1.3.0.jar:9b04edc75d19db54f1b4e8b5355e9364384c6cf71eb0a1b9724c159d779879f8',
|
'org.beanshell:bsh:1.3.0:bsh-1.3.0.jar:9b04edc75d19db54f1b4e8b5355e9364384c6cf71eb0a1b9724c159d779879f8',
|
||||||
'org.bitlet:weupnp:0.1.4:weupnp-0.1.4.jar:88df7e6504929d00bdb832863761385c68ab92af945b04f0770b126270a444fb',
|
'org.bitlet:weupnp:0.1.4:weupnp-0.1.4.jar:88df7e6504929d00bdb832863761385c68ab92af945b04f0770b126270a444fb',
|
||||||
|
'org.codehaus.mojo.signature:java16:1.1:java16-1.1.signature:53799223a2c98dba2d0add810bed76315460df285c69e4f397ae6098f87dd619',
|
||||||
|
'org.codehaus.mojo:animal-sniffer-ant-tasks:1.16:animal-sniffer-ant-tasks-1.16.jar:890040976fbe2d584619a6a61b1fd2e925b3b5eb342a85eb2762c467c0d64e90',
|
||||||
|
'org.codehaus.mojo:animal-sniffer:1.16:animal-sniffer-1.16.jar:72be8bcc226ba43b937c722a08a07852bfa1b11400089265d5df0ee7b38b1d52',
|
||||||
'org.hamcrest:hamcrest-core:1.3:hamcrest-core-1.3.jar:66fdef91e9739348df7a096aa384a5685f4e875584cce89386a7a47251c4d8e9',
|
'org.hamcrest:hamcrest-core:1.3:hamcrest-core-1.3.jar:66fdef91e9739348df7a096aa384a5685f4e875584cce89386a7a47251c4d8e9',
|
||||||
'org.hamcrest:hamcrest-library:1.3:hamcrest-library-1.3.jar:711d64522f9ec410983bd310934296da134be4254a125080a0416ec178dfad1c',
|
'org.hamcrest:hamcrest-library:1.3:hamcrest-library-1.3.jar:711d64522f9ec410983bd310934296da134be4254a125080a0416ec178dfad1c',
|
||||||
'org.hsqldb:hsqldb:2.3.5:hsqldb-2.3.5.jar:6676a6977ac98997a80f827ddbd3fe8ca1e0853dad1492512135fd1a222ccfad',
|
'org.hsqldb:hsqldb:2.3.5:hsqldb-2.3.5.jar:6676a6977ac98997a80f827ddbd3fe8ca1e0853dad1492512135fd1a222ccfad',
|
||||||
@@ -52,6 +58,7 @@ dependencyVerification {
|
|||||||
'org.jmock:jmock-testjar:2.8.2:jmock-testjar-2.8.2.jar:8900860f72c474e027cf97fe78dcbf154a1aa7fc62b6845c5fb4e4f3c7bc8760',
|
'org.jmock:jmock-testjar:2.8.2:jmock-testjar-2.8.2.jar:8900860f72c474e027cf97fe78dcbf154a1aa7fc62b6845c5fb4e4f3c7bc8760',
|
||||||
'org.jmock:jmock:2.8.2:jmock-2.8.2.jar:6c73cb4a2e6dbfb61fd99c9a768539c170ab6568e57846bd60dbf19596b65b16',
|
'org.jmock:jmock:2.8.2:jmock-2.8.2.jar:6c73cb4a2e6dbfb61fd99c9a768539c170ab6568e57846bd60dbf19596b65b16',
|
||||||
'org.objenesis:objenesis:2.1:objenesis-2.1.jar:c74330cc6b806c804fd37e74487b4fe5d7c2750c5e15fbc6efa13bdee1bdef80',
|
'org.objenesis:objenesis:2.1:objenesis-2.1.jar:c74330cc6b806c804fd37e74487b4fe5d7c2750c5e15fbc6efa13bdee1bdef80',
|
||||||
|
'org.ow2.asm:asm-all:5.2:asm-all-5.2.jar:7fbffbc1db3422e2101689fd88df8384b15817b52b9b2b267b9f6d2511dc198d',
|
||||||
'org.ow2.asm:asm:5.0.4:asm-5.0.4.jar:896618ed8ae62702521a78bc7be42b7c491a08e6920a15f89a3ecdec31e9a220',
|
'org.ow2.asm:asm:5.0.4:asm-5.0.4.jar:896618ed8ae62702521a78bc7be42b7c491a08e6920a15f89a3ecdec31e9a220',
|
||||||
'org.whispersystems:curve25519-java:0.4.1:curve25519-java-0.4.1.jar:7dd659d8822c06c3aea1a47f18fac9e5761e29cab8100030b877db445005f03e',
|
'org.whispersystems:curve25519-java:0.4.1:curve25519-java-0.4.1.jar:7dd659d8822c06c3aea1a47f18fac9e5761e29cab8100030b877db445005f03e',
|
||||||
]
|
]
|
||||||
@@ -68,8 +75,3 @@ task jarTest(type: Jar, dependsOn: testClasses) {
|
|||||||
artifacts {
|
artifacts {
|
||||||
testOutput jarTest
|
testOutput jarTest
|
||||||
}
|
}
|
||||||
|
|
||||||
// If a Java 6 JRE is available, check we're not using any Java 7 or 8 APIs
|
|
||||||
tasks.withType(JavaCompile) {
|
|
||||||
useJava6StandardLibrary(it)
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import org.briarproject.bramble.identity.IdentityModule;
|
|||||||
import org.briarproject.bramble.lifecycle.LifecycleModule;
|
import org.briarproject.bramble.lifecycle.LifecycleModule;
|
||||||
import org.briarproject.bramble.plugin.PluginModule;
|
import org.briarproject.bramble.plugin.PluginModule;
|
||||||
import org.briarproject.bramble.properties.PropertiesModule;
|
import org.briarproject.bramble.properties.PropertiesModule;
|
||||||
|
import org.briarproject.bramble.reporting.ReportingModule;
|
||||||
import org.briarproject.bramble.sync.SyncModule;
|
import org.briarproject.bramble.sync.SyncModule;
|
||||||
import org.briarproject.bramble.system.SystemModule;
|
import org.briarproject.bramble.system.SystemModule;
|
||||||
import org.briarproject.bramble.transport.TransportModule;
|
import org.briarproject.bramble.transport.TransportModule;
|
||||||
@@ -28,6 +29,8 @@ public interface BrambleCoreEagerSingletons {
|
|||||||
|
|
||||||
void inject(PropertiesModule.EagerSingletons init);
|
void inject(PropertiesModule.EagerSingletons init);
|
||||||
|
|
||||||
|
void inject(ReportingModule.EagerSingletons init);
|
||||||
|
|
||||||
void inject(SyncModule.EagerSingletons init);
|
void inject(SyncModule.EagerSingletons init);
|
||||||
|
|
||||||
void inject(SystemModule.EagerSingletons init);
|
void inject(SystemModule.EagerSingletons init);
|
||||||
|
|||||||
@@ -59,6 +59,7 @@ public class BrambleCoreModule {
|
|||||||
c.inject(new LifecycleModule.EagerSingletons());
|
c.inject(new LifecycleModule.EagerSingletons());
|
||||||
c.inject(new PluginModule.EagerSingletons());
|
c.inject(new PluginModule.EagerSingletons());
|
||||||
c.inject(new PropertiesModule.EagerSingletons());
|
c.inject(new PropertiesModule.EagerSingletons());
|
||||||
|
c.inject(new ReportingModule.EagerSingletons());
|
||||||
c.inject(new SyncModule.EagerSingletons());
|
c.inject(new SyncModule.EagerSingletons());
|
||||||
c.inject(new SystemModule.EagerSingletons());
|
c.inject(new SystemModule.EagerSingletons());
|
||||||
c.inject(new TransportModule.EagerSingletons());
|
c.inject(new TransportModule.EagerSingletons());
|
||||||
|
|||||||
@@ -5,12 +5,12 @@ import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
|||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.Queue;
|
import java.util.Queue;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
import java.util.logging.Level;
|
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import javax.annotation.concurrent.GuardedBy;
|
import javax.annotation.concurrent.GuardedBy;
|
||||||
|
|
||||||
import static java.util.logging.Level.FINE;
|
import static java.util.logging.Level.FINE;
|
||||||
|
import static org.briarproject.bramble.util.LogUtils.now;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An {@link Executor} that delegates its tasks to another {@link Executor}
|
* An {@link Executor} that delegates its tasks to another {@link Executor}
|
||||||
@@ -20,8 +20,6 @@ import static java.util.logging.Level.FINE;
|
|||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
public class PoliteExecutor implements Executor {
|
public class PoliteExecutor implements Executor {
|
||||||
|
|
||||||
private static final Level LOG_LEVEL = FINE;
|
|
||||||
|
|
||||||
private final Object lock = new Object();
|
private final Object lock = new Object();
|
||||||
@GuardedBy("lock")
|
@GuardedBy("lock")
|
||||||
private final Queue<Runnable> queue = new LinkedList<>();
|
private final Queue<Runnable> queue = new LinkedList<>();
|
||||||
@@ -49,11 +47,11 @@ public class PoliteExecutor implements Executor {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void execute(Runnable r) {
|
public void execute(Runnable r) {
|
||||||
long submitted = System.currentTimeMillis();
|
long submitted = now();
|
||||||
Runnable wrapped = () -> {
|
Runnable wrapped = () -> {
|
||||||
if (log.isLoggable(LOG_LEVEL)) {
|
if (log.isLoggable(FINE)) {
|
||||||
long queued = System.currentTimeMillis() - submitted;
|
long queued = now() - submitted;
|
||||||
log.log(LOG_LEVEL, "Queue time " + queued + " ms");
|
log.fine("Queue time " + queued + " ms");
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
r.run();
|
r.run();
|
||||||
|
|||||||
@@ -6,16 +6,14 @@ import java.util.concurrent.BlockingQueue;
|
|||||||
import java.util.concurrent.RejectedExecutionHandler;
|
import java.util.concurrent.RejectedExecutionHandler;
|
||||||
import java.util.concurrent.ThreadPoolExecutor;
|
import java.util.concurrent.ThreadPoolExecutor;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.logging.Level;
|
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import static java.util.logging.Level.FINE;
|
import static java.util.logging.Level.FINE;
|
||||||
|
import static org.briarproject.bramble.util.LogUtils.now;
|
||||||
|
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
public class TimeLoggingExecutor extends ThreadPoolExecutor {
|
public class TimeLoggingExecutor extends ThreadPoolExecutor {
|
||||||
|
|
||||||
private static final Level LOG_LEVEL = FINE;
|
|
||||||
|
|
||||||
private final Logger log;
|
private final Logger log;
|
||||||
|
|
||||||
public TimeLoggingExecutor(String tag, int corePoolSize, int maxPoolSize,
|
public TimeLoggingExecutor(String tag, int corePoolSize, int maxPoolSize,
|
||||||
@@ -29,15 +27,15 @@ public class TimeLoggingExecutor extends ThreadPoolExecutor {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void execute(Runnable r) {
|
public void execute(Runnable r) {
|
||||||
if (log.isLoggable(LOG_LEVEL)) {
|
if (log.isLoggable(FINE)) {
|
||||||
long submitted = System.currentTimeMillis();
|
long submitted = now();
|
||||||
super.execute(() -> {
|
super.execute(() -> {
|
||||||
long started = System.currentTimeMillis();
|
long started = now();
|
||||||
long queued = started - submitted;
|
long queued = started - submitted;
|
||||||
log.log(LOG_LEVEL, "Queue time " + queued + " ms");
|
log.fine("Queue time " + queued + " ms");
|
||||||
r.run();
|
r.run();
|
||||||
long executing = System.currentTimeMillis() - started;
|
long executing = now() - started;
|
||||||
log.log(LOG_LEVEL, "Execution time " + executing + " ms");
|
log.fine("Execution time " + executing + " ms");
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
super.execute(r);
|
super.execute(r);
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ import javax.inject.Inject;
|
|||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
import static org.briarproject.bramble.api.contact.RecordTypes.CONTACT_INFO;
|
import static org.briarproject.bramble.api.contact.RecordTypes.CONTACT_INFO;
|
||||||
import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_SIGNATURE_LENGTH;
|
import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_SIGNATURE_LENGTH;
|
||||||
|
import static org.briarproject.bramble.util.LogUtils.logException;
|
||||||
import static org.briarproject.bramble.util.ValidationUtils.checkLength;
|
import static org.briarproject.bramble.util.ValidationUtils.checkLength;
|
||||||
import static org.briarproject.bramble.util.ValidationUtils.checkSize;
|
import static org.briarproject.bramble.util.ValidationUtils.checkSize;
|
||||||
|
|
||||||
@@ -122,7 +123,7 @@ class ContactExchangeTaskImpl extends Thread implements ContactExchangeTask {
|
|||||||
in = conn.getReader().getInputStream();
|
in = conn.getReader().getInputStream();
|
||||||
out = conn.getWriter().getOutputStream();
|
out = conn.getWriter().getOutputStream();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
logException(LOG, WARNING, e);
|
||||||
listener.contactExchangeFailed();
|
listener.contactExchangeFailed();
|
||||||
tryToClose(conn);
|
tryToClose(conn);
|
||||||
return;
|
return;
|
||||||
@@ -133,7 +134,7 @@ class ContactExchangeTaskImpl extends Thread implements ContactExchangeTask {
|
|||||||
try {
|
try {
|
||||||
localProperties = transportPropertyManager.getLocalProperties();
|
localProperties = transportPropertyManager.getLocalProperties();
|
||||||
} catch (DbException e) {
|
} catch (DbException e) {
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
logException(LOG, WARNING, e);
|
||||||
listener.contactExchangeFailed();
|
listener.contactExchangeFailed();
|
||||||
tryToClose(conn);
|
tryToClose(conn);
|
||||||
return;
|
return;
|
||||||
@@ -194,7 +195,7 @@ class ContactExchangeTaskImpl extends Thread implements ContactExchangeTask {
|
|||||||
LOG.info("End of stream");
|
LOG.info("End of stream");
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
logException(LOG, WARNING, e);
|
||||||
listener.contactExchangeFailed();
|
listener.contactExchangeFailed();
|
||||||
tryToClose(conn);
|
tryToClose(conn);
|
||||||
return;
|
return;
|
||||||
@@ -222,11 +223,11 @@ class ContactExchangeTaskImpl extends Thread implements ContactExchangeTask {
|
|||||||
LOG.info("Pseudonym exchange succeeded");
|
LOG.info("Pseudonym exchange succeeded");
|
||||||
listener.contactExchangeSucceeded(remoteInfo.author);
|
listener.contactExchangeSucceeded(remoteInfo.author);
|
||||||
} catch (ContactExistsException e) {
|
} catch (ContactExistsException e) {
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
logException(LOG, WARNING, e);
|
||||||
tryToClose(conn);
|
tryToClose(conn);
|
||||||
listener.duplicateContact(remoteInfo.author);
|
listener.duplicateContact(remoteInfo.author);
|
||||||
} catch (DbException e) {
|
} catch (DbException e) {
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
logException(LOG, WARNING, e);
|
||||||
tryToClose(conn);
|
tryToClose(conn);
|
||||||
listener.contactExchangeFailed();
|
listener.contactExchangeFailed();
|
||||||
}
|
}
|
||||||
@@ -307,7 +308,7 @@ class ContactExchangeTaskImpl extends Thread implements ContactExchangeTask {
|
|||||||
conn.getReader().dispose(true, true);
|
conn.getReader().dispose(true, true);
|
||||||
conn.getWriter().dispose(true);
|
conn.getWriter().dispose(true);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
logException(LOG, WARNING, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ class ContactManagerImpl implements ContactManager {
|
|||||||
SecretKey master, long timestamp, boolean alice, boolean verified,
|
SecretKey master, long timestamp, boolean alice, boolean verified,
|
||||||
boolean active) throws DbException {
|
boolean active) throws DbException {
|
||||||
ContactId c = db.addContact(txn, remote, local, verified, active);
|
ContactId c = db.addContact(txn, remote, local, verified, active);
|
||||||
keyManager.addContact(txn, c, master, timestamp, alice);
|
keyManager.addContact(txn, c, master, timestamp, alice, active);
|
||||||
Contact contact = db.getContact(txn, c);
|
Contact contact = db.getContact(txn, c);
|
||||||
for (ContactHook hook : hooks) hook.addingContact(txn, contact);
|
for (ContactHook hook : hooks) hook.addingContact(txn, contact);
|
||||||
return c;
|
return c;
|
||||||
|
|||||||
@@ -32,6 +32,8 @@ import javax.inject.Inject;
|
|||||||
|
|
||||||
import static java.util.logging.Level.INFO;
|
import static java.util.logging.Level.INFO;
|
||||||
import static org.briarproject.bramble.util.ByteUtils.INT_32_BYTES;
|
import static org.briarproject.bramble.util.ByteUtils.INT_32_BYTES;
|
||||||
|
import static org.briarproject.bramble.util.LogUtils.logDuration;
|
||||||
|
import static org.briarproject.bramble.util.LogUtils.now;
|
||||||
|
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
class CryptoComponentImpl implements CryptoComponent {
|
class CryptoComponentImpl implements CryptoComponent {
|
||||||
@@ -127,16 +129,14 @@ class CryptoComponentImpl implements CryptoComponent {
|
|||||||
throw new IllegalArgumentException();
|
throw new IllegalArgumentException();
|
||||||
if (!(pub instanceof Curve25519PublicKey))
|
if (!(pub instanceof Curve25519PublicKey))
|
||||||
throw new IllegalArgumentException();
|
throw new IllegalArgumentException();
|
||||||
long now = System.currentTimeMillis();
|
long start = now();
|
||||||
byte[] secret = curve25519.calculateAgreement(pub.getEncoded(),
|
byte[] secret = curve25519.calculateAgreement(pub.getEncoded(),
|
||||||
priv.getEncoded());
|
priv.getEncoded());
|
||||||
// If the shared secret is all zeroes, the public key is invalid
|
// If the shared secret is all zeroes, the public key is invalid
|
||||||
byte allZero = 0;
|
byte allZero = 0;
|
||||||
for (byte b : secret) allZero |= b;
|
for (byte b : secret) allZero |= b;
|
||||||
if (allZero == 0) throw new GeneralSecurityException();
|
if (allZero == 0) throw new GeneralSecurityException();
|
||||||
long duration = System.currentTimeMillis() - now;
|
logDuration(LOG, "Deriving shared secret", start);
|
||||||
if (LOG.isLoggable(INFO))
|
|
||||||
LOG.info("Deriving shared secret took " + duration + " ms");
|
|
||||||
return secret;
|
return secret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -152,59 +152,47 @@ public class MessageEncrypter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void main(String[] args) throws Exception {
|
public static void main(String[] args) {
|
||||||
if (args.length < 1) {
|
if (args.length < 1) {
|
||||||
printUsage();
|
printUsage();
|
||||||
return;
|
System.exit(1);
|
||||||
}
|
}
|
||||||
SecureRandom random = new SecureRandom();
|
|
||||||
MessageEncrypter encrypter = new MessageEncrypter(random);
|
|
||||||
if (args[0].equals("generate")) {
|
if (args[0].equals("generate")) {
|
||||||
if (args.length != 3) {
|
if (args.length != 3) {
|
||||||
printUsage();
|
printUsage();
|
||||||
return;
|
System.exit(1);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
generateKeyPair(args[1], args[2]);
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
System.exit(2);
|
||||||
}
|
}
|
||||||
// Generate a key pair
|
|
||||||
KeyPair keyPair = encrypter.generateKeyPair();
|
|
||||||
PrintStream out = new PrintStream(new FileOutputStream(args[1]));
|
|
||||||
out.print(
|
|
||||||
StringUtils.toHexString(keyPair.getPublic().getEncoded()));
|
|
||||||
out.flush();
|
|
||||||
out.close();
|
|
||||||
out = new PrintStream(new FileOutputStream(args[2]));
|
|
||||||
out.print(
|
|
||||||
StringUtils.toHexString(keyPair.getPrivate().getEncoded()));
|
|
||||||
out.flush();
|
|
||||||
out.close();
|
|
||||||
} else if (args[0].equals("encrypt")) {
|
} else if (args[0].equals("encrypt")) {
|
||||||
if (args.length != 2) {
|
if (args.length != 2) {
|
||||||
printUsage();
|
printUsage();
|
||||||
return;
|
System.exit(1);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
encryptMessage(args[1]);
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
System.exit(2);
|
||||||
}
|
}
|
||||||
// Encrypt a decrypted message
|
|
||||||
InputStream in = new FileInputStream(args[1]);
|
|
||||||
byte[] keyBytes = StringUtils.fromHexString(readFully(in).trim());
|
|
||||||
PublicKey publicKey =
|
|
||||||
encrypter.getKeyParser().parsePublicKey(keyBytes);
|
|
||||||
String message = readFully(System.in);
|
|
||||||
byte[] plaintext = message.getBytes(Charset.forName("UTF-8"));
|
|
||||||
byte[] ciphertext = encrypter.encrypt(publicKey, plaintext);
|
|
||||||
System.out.println(AsciiArmour.wrap(ciphertext, LINE_LENGTH));
|
|
||||||
} else if (args[0].equals("decrypt")) {
|
} else if (args[0].equals("decrypt")) {
|
||||||
if (args.length != 2) {
|
if (args.length != 2) {
|
||||||
printUsage();
|
printUsage();
|
||||||
return;
|
System.exit(1);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
decryptMessage(args[1]);
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
System.exit(2);
|
||||||
}
|
}
|
||||||
// Decrypt an encrypted message
|
|
||||||
InputStream in = new FileInputStream(args[1]);
|
|
||||||
byte[] keyBytes = StringUtils.fromHexString(readFully(in).trim());
|
|
||||||
PrivateKey privateKey =
|
|
||||||
encrypter.getKeyParser().parsePrivateKey(keyBytes);
|
|
||||||
byte[] ciphertext = AsciiArmour.unwrap(readFully(System.in));
|
|
||||||
byte[] plaintext = encrypter.decrypt(privateKey, ciphertext);
|
|
||||||
System.out.println(new String(plaintext, Charset.forName("UTF-8")));
|
|
||||||
} else {
|
} else {
|
||||||
printUsage();
|
printUsage();
|
||||||
|
System.exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -216,6 +204,46 @@ public class MessageEncrypter {
|
|||||||
System.err.println("MessageEncrypter decrypt <private_key_file>");
|
System.err.println("MessageEncrypter decrypt <private_key_file>");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void generateKeyPair(String publicKeyFile,
|
||||||
|
String privateKeyFile) throws Exception {
|
||||||
|
SecureRandom random = new SecureRandom();
|
||||||
|
MessageEncrypter encrypter = new MessageEncrypter(random);
|
||||||
|
KeyPair keyPair = encrypter.generateKeyPair();
|
||||||
|
PrintStream out = new PrintStream(new FileOutputStream(publicKeyFile));
|
||||||
|
out.print(StringUtils.toHexString(keyPair.getPublic().getEncoded()));
|
||||||
|
out.flush();
|
||||||
|
out.close();
|
||||||
|
out = new PrintStream(new FileOutputStream(privateKeyFile));
|
||||||
|
out.print(StringUtils.toHexString(keyPair.getPrivate().getEncoded()));
|
||||||
|
out.flush();
|
||||||
|
out.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void encryptMessage(String publicKeyFile) throws Exception {
|
||||||
|
SecureRandom random = new SecureRandom();
|
||||||
|
MessageEncrypter encrypter = new MessageEncrypter(random);
|
||||||
|
InputStream in = new FileInputStream(publicKeyFile);
|
||||||
|
byte[] keyBytes = StringUtils.fromHexString(readFully(in).trim());
|
||||||
|
PublicKey publicKey =
|
||||||
|
encrypter.getKeyParser().parsePublicKey(keyBytes);
|
||||||
|
String message = readFully(System.in);
|
||||||
|
byte[] plaintext = message.getBytes(Charset.forName("UTF-8"));
|
||||||
|
byte[] ciphertext = encrypter.encrypt(publicKey, plaintext);
|
||||||
|
System.out.println(AsciiArmour.wrap(ciphertext, LINE_LENGTH));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void decryptMessage(String privateKeyFile) throws Exception {
|
||||||
|
SecureRandom random = new SecureRandom();
|
||||||
|
MessageEncrypter encrypter = new MessageEncrypter(random);
|
||||||
|
InputStream in = new FileInputStream(privateKeyFile);
|
||||||
|
byte[] keyBytes = StringUtils.fromHexString(readFully(in).trim());
|
||||||
|
PrivateKey privateKey =
|
||||||
|
encrypter.getKeyParser().parsePrivateKey(keyBytes);
|
||||||
|
byte[] ciphertext = AsciiArmour.unwrap(readFully(System.in));
|
||||||
|
byte[] plaintext = encrypter.decrypt(privateKey, ciphertext);
|
||||||
|
System.out.println(new String(plaintext, Charset.forName("UTF-8")));
|
||||||
|
}
|
||||||
|
|
||||||
private static String readFully(InputStream in) throws IOException {
|
private static String readFully(InputStream in) throws IOException {
|
||||||
String newline = System.getProperty("line.separator");
|
String newline = System.getProperty("line.separator");
|
||||||
StringBuilder stringBuilder = new StringBuilder();
|
StringBuilder stringBuilder = new StringBuilder();
|
||||||
|
|||||||
@@ -10,6 +10,8 @@ import java.util.logging.Logger;
|
|||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
import static java.util.logging.Level.INFO;
|
import static java.util.logging.Level.INFO;
|
||||||
|
import static org.briarproject.bramble.util.LogUtils.logDuration;
|
||||||
|
import static org.briarproject.bramble.util.LogUtils.now;
|
||||||
|
|
||||||
class ScryptKdf implements PasswordBasedKdf {
|
class ScryptKdf implements PasswordBasedKdf {
|
||||||
|
|
||||||
@@ -50,13 +52,11 @@ class ScryptKdf implements PasswordBasedKdf {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SecretKey deriveKey(String password, byte[] salt, int cost) {
|
public SecretKey deriveKey(String password, byte[] salt, int cost) {
|
||||||
long start = System.currentTimeMillis();
|
long start = now();
|
||||||
byte[] passwordBytes = StringUtils.toUtf8(password);
|
byte[] passwordBytes = StringUtils.toUtf8(password);
|
||||||
SecretKey k = new SecretKey(SCrypt.generate(passwordBytes, salt, cost,
|
SecretKey k = new SecretKey(SCrypt.generate(passwordBytes, salt, cost,
|
||||||
BLOCK_SIZE, PARALLELIZATION, SecretKey.LENGTH));
|
BLOCK_SIZE, PARALLELIZATION, SecretKey.LENGTH));
|
||||||
long duration = System.currentTimeMillis() - start;
|
logDuration(LOG, "Deriving key from password", start);
|
||||||
if (LOG.isLoggable(INFO))
|
|
||||||
LOG.info("Deriving key from password took " + duration + " ms");
|
|
||||||
return k;
|
return k;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,8 @@ import java.util.logging.Logger;
|
|||||||
|
|
||||||
import javax.annotation.concurrent.Immutable;
|
import javax.annotation.concurrent.Immutable;
|
||||||
|
|
||||||
import static java.util.logging.Level.INFO;
|
import static org.briarproject.bramble.util.LogUtils.logDuration;
|
||||||
|
import static org.briarproject.bramble.util.LogUtils.now;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A key parser that uses the encoding defined in "SEC 1: Elliptic Curve
|
* A key parser that uses the encoding defined in "SEC 1: Elliptic Curve
|
||||||
@@ -48,7 +49,7 @@ class Sec1KeyParser implements KeyParser {
|
|||||||
throws GeneralSecurityException {
|
throws GeneralSecurityException {
|
||||||
// The validation procedure comes from SEC 1, section 3.2.2.1. Note
|
// The validation procedure comes from SEC 1, section 3.2.2.1. Note
|
||||||
// that SEC 1 parameter names are used below, not RFC 5639 names
|
// that SEC 1 parameter names are used below, not RFC 5639 names
|
||||||
long now = System.currentTimeMillis();
|
long start = now();
|
||||||
if (encodedKey.length != publicKeyBytes)
|
if (encodedKey.length != publicKeyBytes)
|
||||||
throw new GeneralSecurityException();
|
throw new GeneralSecurityException();
|
||||||
// The first byte must be 0x04
|
// The first byte must be 0x04
|
||||||
@@ -80,16 +81,14 @@ class Sec1KeyParser implements KeyParser {
|
|||||||
// Construct a public key from the point (x, y) and the params
|
// Construct a public key from the point (x, y) and the params
|
||||||
ECPublicKeyParameters k = new ECPublicKeyParameters(pub, params);
|
ECPublicKeyParameters k = new ECPublicKeyParameters(pub, params);
|
||||||
PublicKey p = new Sec1PublicKey(k);
|
PublicKey p = new Sec1PublicKey(k);
|
||||||
long duration = System.currentTimeMillis() - now;
|
logDuration(LOG, "Parsing public key", start);
|
||||||
if (LOG.isLoggable(INFO))
|
|
||||||
LOG.info("Parsing public key took " + duration + " ms");
|
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PrivateKey parsePrivateKey(byte[] encodedKey)
|
public PrivateKey parsePrivateKey(byte[] encodedKey)
|
||||||
throws GeneralSecurityException {
|
throws GeneralSecurityException {
|
||||||
long now = System.currentTimeMillis();
|
long start = now();
|
||||||
if (encodedKey.length != privateKeyBytes)
|
if (encodedKey.length != privateKeyBytes)
|
||||||
throw new GeneralSecurityException();
|
throw new GeneralSecurityException();
|
||||||
BigInteger d = new BigInteger(1, encodedKey); // Positive signum
|
BigInteger d = new BigInteger(1, encodedKey); // Positive signum
|
||||||
@@ -99,9 +98,7 @@ class Sec1KeyParser implements KeyParser {
|
|||||||
// Construct a private key from the private value and the params
|
// Construct a private key from the private value and the params
|
||||||
ECPrivateKeyParameters k = new ECPrivateKeyParameters(d, params);
|
ECPrivateKeyParameters k = new ECPrivateKeyParameters(d, params);
|
||||||
PrivateKey p = new Sec1PrivateKey(k, keyBits);
|
PrivateKey p = new Sec1PrivateKey(k, keyBits);
|
||||||
long duration = System.currentTimeMillis() - now;
|
logDuration(LOG, "Parsing private key", start);
|
||||||
if (LOG.isLoggable(INFO))
|
|
||||||
LOG.info("Parsing private key took " + duration + " ms");
|
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import java.io.InputStream;
|
|||||||
|
|
||||||
import javax.annotation.concurrent.Immutable;
|
import javax.annotation.concurrent.Immutable;
|
||||||
|
|
||||||
|
import static org.briarproject.bramble.api.data.BdfReader.DEFAULT_MAX_BUFFER_SIZE;
|
||||||
import static org.briarproject.bramble.api.data.BdfReader.DEFAULT_NESTED_LIMIT;
|
import static org.briarproject.bramble.api.data.BdfReader.DEFAULT_NESTED_LIMIT;
|
||||||
|
|
||||||
@Immutable
|
@Immutable
|
||||||
@@ -16,11 +17,13 @@ class BdfReaderFactoryImpl implements BdfReaderFactory {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public BdfReader createReader(InputStream in) {
|
public BdfReader createReader(InputStream in) {
|
||||||
return new BdfReaderImpl(in, DEFAULT_NESTED_LIMIT);
|
return new BdfReaderImpl(in, DEFAULT_NESTED_LIMIT,
|
||||||
|
DEFAULT_MAX_BUFFER_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public BdfReader createReader(InputStream in, int nestedLimit) {
|
public BdfReader createReader(InputStream in, int nestedLimit,
|
||||||
return new BdfReaderImpl(in, nestedLimit);
|
int maxBufferSize) {
|
||||||
|
return new BdfReaderImpl(in, nestedLimit, maxBufferSize);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,15 +37,16 @@ class BdfReaderImpl implements BdfReader {
|
|||||||
private static final byte[] EMPTY_BUFFER = new byte[0];
|
private static final byte[] EMPTY_BUFFER = new byte[0];
|
||||||
|
|
||||||
private final InputStream in;
|
private final InputStream in;
|
||||||
private final int nestedLimit;
|
private final int nestedLimit, maxBufferSize;
|
||||||
|
|
||||||
private boolean hasLookahead = false, eof = false;
|
private boolean hasLookahead = false, eof = false;
|
||||||
private byte next;
|
private byte next;
|
||||||
private byte[] buf = new byte[8];
|
private byte[] buf = new byte[8];
|
||||||
|
|
||||||
BdfReaderImpl(InputStream in, int nestedLimit) {
|
BdfReaderImpl(InputStream in, int nestedLimit, int maxBufferSize) {
|
||||||
this.in = in;
|
this.in = in;
|
||||||
this.nestedLimit = nestedLimit;
|
this.nestedLimit = nestedLimit;
|
||||||
|
this.maxBufferSize = maxBufferSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void readLookahead() throws IOException {
|
private void readLookahead() throws IOException {
|
||||||
@@ -91,8 +92,8 @@ class BdfReaderImpl implements BdfReader {
|
|||||||
if (hasBoolean()) return readBoolean();
|
if (hasBoolean()) return readBoolean();
|
||||||
if (hasLong()) return readLong();
|
if (hasLong()) return readLong();
|
||||||
if (hasDouble()) return readDouble();
|
if (hasDouble()) return readDouble();
|
||||||
if (hasString()) return readString(Integer.MAX_VALUE);
|
if (hasString()) return readString();
|
||||||
if (hasRaw()) return readRaw(Integer.MAX_VALUE);
|
if (hasRaw()) return readRaw();
|
||||||
if (hasList()) return readList(level);
|
if (hasList()) return readList(level);
|
||||||
if (hasDictionary()) return readDictionary(level);
|
if (hasDictionary()) return readDictionary(level);
|
||||||
throw new FormatException();
|
throw new FormatException();
|
||||||
@@ -245,11 +246,11 @@ class BdfReaderImpl implements BdfReader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String readString(int maxLength) throws IOException {
|
public String readString() throws IOException {
|
||||||
if (!hasString()) throw new FormatException();
|
if (!hasString()) throw new FormatException();
|
||||||
hasLookahead = false;
|
hasLookahead = false;
|
||||||
int length = readStringLength();
|
int length = readStringLength();
|
||||||
if (length < 0 || length > maxLength) throw new FormatException();
|
if (length < 0 || length > maxBufferSize) throw new FormatException();
|
||||||
if (length == 0) return "";
|
if (length == 0) return "";
|
||||||
readIntoBuffer(length);
|
readIntoBuffer(length);
|
||||||
return new String(buf, 0, length, "UTF-8");
|
return new String(buf, 0, length, "UTF-8");
|
||||||
@@ -279,11 +280,11 @@ class BdfReaderImpl implements BdfReader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public byte[] readRaw(int maxLength) throws IOException {
|
public byte[] readRaw() throws IOException {
|
||||||
if (!hasRaw()) throw new FormatException();
|
if (!hasRaw()) throw new FormatException();
|
||||||
hasLookahead = false;
|
hasLookahead = false;
|
||||||
int length = readRawLength();
|
int length = readRawLength();
|
||||||
if (length < 0 || length > maxLength) throw new FormatException();
|
if (length < 0 || length > maxBufferSize) throw new FormatException();
|
||||||
if (length == 0) return EMPTY_BUFFER;
|
if (length == 0) return EMPTY_BUFFER;
|
||||||
byte[] b = new byte[length];
|
byte[] b = new byte[length];
|
||||||
readIntoBuffer(b, length);
|
readIntoBuffer(b, length);
|
||||||
@@ -381,7 +382,7 @@ class BdfReaderImpl implements BdfReader {
|
|||||||
BdfDictionary dictionary = new BdfDictionary();
|
BdfDictionary dictionary = new BdfDictionary();
|
||||||
readDictionaryStart();
|
readDictionaryStart();
|
||||||
while (!hasDictionaryEnd())
|
while (!hasDictionaryEnd())
|
||||||
dictionary.put(readString(Integer.MAX_VALUE), readObject(level + 1));
|
dictionary.put(readString(), readObject(level + 1));
|
||||||
readDictionaryEnd();
|
readDictionaryEnd();
|
||||||
return dictionary;
|
return dictionary;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -59,8 +59,8 @@ class MetadataParserImpl implements MetadataParser {
|
|||||||
if (reader.hasBoolean()) return reader.readBoolean();
|
if (reader.hasBoolean()) return reader.readBoolean();
|
||||||
if (reader.hasLong()) return reader.readLong();
|
if (reader.hasLong()) return reader.readLong();
|
||||||
if (reader.hasDouble()) return reader.readDouble();
|
if (reader.hasDouble()) return reader.readDouble();
|
||||||
if (reader.hasString()) return reader.readString(Integer.MAX_VALUE);
|
if (reader.hasString()) return reader.readString();
|
||||||
if (reader.hasRaw()) return reader.readRaw(Integer.MAX_VALUE);
|
if (reader.hasRaw()) return reader.readRaw();
|
||||||
if (reader.hasList()) return reader.readList();
|
if (reader.hasList()) return reader.readList();
|
||||||
if (reader.hasDictionary()) return reader.readDictionary();
|
if (reader.hasDictionary()) return reader.readDictionary();
|
||||||
throw new FormatException();
|
throw new FormatException();
|
||||||
|
|||||||
@@ -125,16 +125,10 @@ interface Database<T> {
|
|||||||
throws DbException;
|
throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stores the given transport keys, optionally binding them to the given
|
* Stores the given transport keys for the given contact and returns a
|
||||||
* contact, and returns a key set ID.
|
* key set ID.
|
||||||
*/
|
*/
|
||||||
KeySetId addTransportKeys(T txn, @Nullable ContactId c, TransportKeys k)
|
KeySetId addTransportKeys(T txn, ContactId c, TransportKeys k)
|
||||||
throws DbException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Binds the given keys for the given transport to the given contact.
|
|
||||||
*/
|
|
||||||
void bindTransportKeys(T txn, ContactId c, TransportId t, KeySetId k)
|
|
||||||
throws DbException;
|
throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -68,13 +68,15 @@ import javax.annotation.Nullable;
|
|||||||
import javax.annotation.concurrent.ThreadSafe;
|
import javax.annotation.concurrent.ThreadSafe;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
import static java.util.logging.Level.FINE;
|
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
import static org.briarproject.bramble.api.sync.Group.Visibility.INVISIBLE;
|
import static org.briarproject.bramble.api.sync.Group.Visibility.INVISIBLE;
|
||||||
import static org.briarproject.bramble.api.sync.Group.Visibility.SHARED;
|
import static org.briarproject.bramble.api.sync.Group.Visibility.SHARED;
|
||||||
import static org.briarproject.bramble.api.sync.ValidationManager.State.DELIVERED;
|
import static org.briarproject.bramble.api.sync.ValidationManager.State.DELIVERED;
|
||||||
import static org.briarproject.bramble.api.sync.ValidationManager.State.UNKNOWN;
|
import static org.briarproject.bramble.api.sync.ValidationManager.State.UNKNOWN;
|
||||||
import static org.briarproject.bramble.db.DatabaseConstants.MAX_OFFERED_MESSAGES;
|
import static org.briarproject.bramble.db.DatabaseConstants.MAX_OFFERED_MESSAGES;
|
||||||
|
import static org.briarproject.bramble.util.LogUtils.logDuration;
|
||||||
|
import static org.briarproject.bramble.util.LogUtils.logException;
|
||||||
|
import static org.briarproject.bramble.util.LogUtils.now;
|
||||||
|
|
||||||
@ThreadSafe
|
@ThreadSafe
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
@@ -108,7 +110,7 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
|
|||||||
try {
|
try {
|
||||||
close();
|
close();
|
||||||
} catch (DbException e) {
|
} catch (DbException e) {
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
logException(LOG, WARNING, e);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return reopened;
|
return reopened;
|
||||||
@@ -125,13 +127,13 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
|
|||||||
// Don't allow reentrant locking
|
// Don't allow reentrant locking
|
||||||
if (lock.getReadHoldCount() > 0) throw new IllegalStateException();
|
if (lock.getReadHoldCount() > 0) throw new IllegalStateException();
|
||||||
if (lock.getWriteHoldCount() > 0) throw new IllegalStateException();
|
if (lock.getWriteHoldCount() > 0) throw new IllegalStateException();
|
||||||
long start = System.currentTimeMillis();
|
long start = now();
|
||||||
if (readOnly) lock.readLock().lock();
|
if (readOnly) {
|
||||||
else lock.writeLock().lock();
|
lock.readLock().lock();
|
||||||
if (LOG.isLoggable(FINE)) {
|
logDuration(LOG, "Waiting for read lock", start);
|
||||||
long duration = System.currentTimeMillis() - start;
|
} else {
|
||||||
if (readOnly) LOG.fine("Waited " + duration + " ms for read lock");
|
lock.writeLock().lock();
|
||||||
else LOG.fine("Waited " + duration + " ms for write lock");
|
logDuration(LOG, "Waiting for write lock", start);
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
return new Transaction(db.startTransaction(), readOnly);
|
return new Transaction(db.startTransaction(), readOnly);
|
||||||
@@ -234,27 +236,15 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public KeySetId addTransportKeys(Transaction transaction,
|
public KeySetId addTransportKeys(Transaction transaction, ContactId c,
|
||||||
@Nullable ContactId c, TransportKeys k) throws DbException {
|
TransportKeys k) throws DbException {
|
||||||
if (transaction.isReadOnly()) throw new IllegalArgumentException();
|
|
||||||
T txn = unbox(transaction);
|
|
||||||
if (c != null && !db.containsContact(txn, c))
|
|
||||||
throw new NoSuchContactException();
|
|
||||||
if (!db.containsTransport(txn, k.getTransportId()))
|
|
||||||
throw new NoSuchTransportException();
|
|
||||||
return db.addTransportKeys(txn, c, k);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void bindTransportKeys(Transaction transaction, ContactId c,
|
|
||||||
TransportId t, KeySetId k) throws DbException {
|
|
||||||
if (transaction.isReadOnly()) throw new IllegalArgumentException();
|
if (transaction.isReadOnly()) throw new IllegalArgumentException();
|
||||||
T txn = unbox(transaction);
|
T txn = unbox(transaction);
|
||||||
if (!db.containsContact(txn, c))
|
if (!db.containsContact(txn, c))
|
||||||
throw new NoSuchContactException();
|
throw new NoSuchContactException();
|
||||||
if (!db.containsTransport(txn, t))
|
if (!db.containsTransport(txn, k.getTransportId()))
|
||||||
throw new NoSuchTransportException();
|
throw new NoSuchTransportException();
|
||||||
db.bindTransportKeys(txn, c, t, k);
|
return db.addTransportKeys(txn, c, k);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -53,6 +53,7 @@ import java.util.logging.Logger;
|
|||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
import static java.sql.Types.INTEGER;
|
import static java.sql.Types.INTEGER;
|
||||||
|
import static java.util.Collections.singletonList;
|
||||||
import static java.util.logging.Level.INFO;
|
import static java.util.logging.Level.INFO;
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
import static org.briarproject.bramble.api.db.Metadata.REMOVE;
|
import static org.briarproject.bramble.api.db.Metadata.REMOVE;
|
||||||
@@ -65,6 +66,7 @@ import static org.briarproject.bramble.api.sync.ValidationManager.State.UNKNOWN;
|
|||||||
import static org.briarproject.bramble.db.DatabaseConstants.DB_SETTINGS_NAMESPACE;
|
import static org.briarproject.bramble.db.DatabaseConstants.DB_SETTINGS_NAMESPACE;
|
||||||
import static org.briarproject.bramble.db.DatabaseConstants.SCHEMA_VERSION_KEY;
|
import static org.briarproject.bramble.db.DatabaseConstants.SCHEMA_VERSION_KEY;
|
||||||
import static org.briarproject.bramble.db.ExponentialBackoff.calculateExpiry;
|
import static org.briarproject.bramble.db.ExponentialBackoff.calculateExpiry;
|
||||||
|
import static org.briarproject.bramble.util.LogUtils.logException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A generic database implementation that can be used with any JDBC-compatible
|
* A generic database implementation that can be used with any JDBC-compatible
|
||||||
@@ -74,7 +76,7 @@ import static org.briarproject.bramble.db.ExponentialBackoff.calculateExpiry;
|
|||||||
abstract class JdbcDatabase implements Database<Connection> {
|
abstract class JdbcDatabase implements Database<Connection> {
|
||||||
|
|
||||||
// Package access for testing
|
// Package access for testing
|
||||||
static final int CODE_SCHEMA_VERSION = 38;
|
static final int CODE_SCHEMA_VERSION = 39;
|
||||||
|
|
||||||
// Rotation period offsets for incoming transport keys
|
// Rotation period offsets for incoming transport keys
|
||||||
private static final int OFFSET_PREV = -1;
|
private static final int OFFSET_PREV = -1;
|
||||||
@@ -236,7 +238,7 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
+ " (transportId _STRING NOT NULL,"
|
+ " (transportId _STRING NOT NULL,"
|
||||||
+ " keySetId _COUNTER,"
|
+ " keySetId _COUNTER,"
|
||||||
+ " rotationPeriod BIGINT NOT NULL,"
|
+ " rotationPeriod BIGINT NOT NULL,"
|
||||||
+ " contactId INT," // Null if keys are not bound
|
+ " contactId INT NOT NULL,"
|
||||||
+ " tagKey _SECRET NOT NULL,"
|
+ " tagKey _SECRET NOT NULL,"
|
||||||
+ " headerKey _SECRET NOT NULL,"
|
+ " headerKey _SECRET NOT NULL,"
|
||||||
+ " stream BIGINT NOT NULL,"
|
+ " stream BIGINT NOT NULL,"
|
||||||
@@ -255,7 +257,7 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
+ " (transportId _STRING NOT NULL,"
|
+ " (transportId _STRING NOT NULL,"
|
||||||
+ " keySetId INT NOT NULL,"
|
+ " keySetId INT NOT NULL,"
|
||||||
+ " rotationPeriod BIGINT NOT NULL,"
|
+ " rotationPeriod BIGINT NOT NULL,"
|
||||||
+ " contactId INT," // Null if keys are not bound
|
+ " contactId INT NOT NULL,"
|
||||||
+ " tagKey _SECRET NOT NULL,"
|
+ " tagKey _SECRET NOT NULL,"
|
||||||
+ " headerKey _SECRET NOT NULL,"
|
+ " headerKey _SECRET NOT NULL,"
|
||||||
+ " base BIGINT NOT NULL,"
|
+ " base BIGINT NOT NULL,"
|
||||||
@@ -389,7 +391,7 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
|
|
||||||
// Package access for testing
|
// Package access for testing
|
||||||
List<Migration<Connection>> getMigrations() {
|
List<Migration<Connection>> getMigrations() {
|
||||||
return Collections.emptyList();
|
return singletonList(new Migration38_39());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void storeSchemaVersion(Connection txn, int version)
|
private void storeSchemaVersion(Connection txn, int version)
|
||||||
@@ -403,7 +405,7 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
try {
|
try {
|
||||||
if (rs != null) rs.close();
|
if (rs != null) rs.close();
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
logException(LOG, WARNING, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -411,7 +413,7 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
try {
|
try {
|
||||||
if (s != null) s.close();
|
if (s != null) s.close();
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
logException(LOG, WARNING, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -508,12 +510,11 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
}
|
}
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
// Try to close the connection
|
// Try to close the connection
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
logException(LOG, WARNING, e);
|
||||||
try {
|
try {
|
||||||
txn.close();
|
txn.close();
|
||||||
} catch (SQLException e1) {
|
} catch (SQLException e1) {
|
||||||
if (LOG.isLoggable(WARNING))
|
logException(LOG, WARNING, e1);
|
||||||
LOG.log(WARNING, e1.toString(), e1);
|
|
||||||
}
|
}
|
||||||
// Whatever happens, allow the database to close
|
// Whatever happens, allow the database to close
|
||||||
connectionsLock.lock();
|
connectionsLock.lock();
|
||||||
@@ -883,7 +884,7 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public KeySetId addTransportKeys(Connection txn, @Nullable ContactId c,
|
public KeySetId addTransportKeys(Connection txn, ContactId c,
|
||||||
TransportKeys k) throws DbException {
|
TransportKeys k) throws DbException {
|
||||||
PreparedStatement ps = null;
|
PreparedStatement ps = null;
|
||||||
ResultSet rs = null;
|
ResultSet rs = null;
|
||||||
@@ -893,8 +894,7 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
+ " rotationPeriod, tagKey, headerKey, stream, active)"
|
+ " rotationPeriod, tagKey, headerKey, stream, active)"
|
||||||
+ " VALUES (?, ?, ?, ?, ?, ?, ?)";
|
+ " VALUES (?, ?, ?, ?, ?, ?, ?)";
|
||||||
ps = txn.prepareStatement(sql);
|
ps = txn.prepareStatement(sql);
|
||||||
if (c == null) ps.setNull(1, INTEGER);
|
ps.setInt(1, c.getInt());
|
||||||
else ps.setInt(1, c.getInt());
|
|
||||||
ps.setString(2, k.getTransportId().getString());
|
ps.setString(2, k.getTransportId().getString());
|
||||||
OutgoingKeys outCurr = k.getCurrentOutgoingKeys();
|
OutgoingKeys outCurr = k.getCurrentOutgoingKeys();
|
||||||
ps.setLong(3, outCurr.getRotationPeriod());
|
ps.setLong(3, outCurr.getRotationPeriod());
|
||||||
@@ -922,8 +922,7 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
+ " VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)";
|
+ " VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)";
|
||||||
ps = txn.prepareStatement(sql);
|
ps = txn.prepareStatement(sql);
|
||||||
ps.setInt(1, keySetId.getInt());
|
ps.setInt(1, keySetId.getInt());
|
||||||
if (c == null) ps.setNull(2, INTEGER);
|
ps.setInt(2, c.getInt());
|
||||||
else ps.setInt(2, c.getInt());
|
|
||||||
ps.setString(3, k.getTransportId().getString());
|
ps.setString(3, k.getTransportId().getString());
|
||||||
// Previous rotation period
|
// Previous rotation period
|
||||||
IncomingKeys inPrev = k.getPreviousIncomingKeys();
|
IncomingKeys inPrev = k.getPreviousIncomingKeys();
|
||||||
@@ -965,33 +964,6 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void bindTransportKeys(Connection txn, ContactId c, TransportId t,
|
|
||||||
KeySetId k) throws DbException {
|
|
||||||
PreparedStatement ps = null;
|
|
||||||
try {
|
|
||||||
String sql = "UPDATE outgoingKeys SET contactId = ?"
|
|
||||||
+ " WHERE keySetId = ?";
|
|
||||||
ps = txn.prepareStatement(sql);
|
|
||||||
ps.setInt(1, c.getInt());
|
|
||||||
ps.setInt(2, k.getInt());
|
|
||||||
int affected = ps.executeUpdate();
|
|
||||||
if (affected < 0) throw new DbStateException();
|
|
||||||
ps.close();
|
|
||||||
sql = "UPDATE incomingKeys SET contactId = ?"
|
|
||||||
+ " WHERE keySetId = ?";
|
|
||||||
ps = txn.prepareStatement(sql);
|
|
||||||
ps.setInt(1, c.getInt());
|
|
||||||
ps.setInt(2, k.getInt());
|
|
||||||
affected = ps.executeUpdate();
|
|
||||||
if (affected < 0) throw new DbStateException();
|
|
||||||
ps.close();
|
|
||||||
} catch (SQLException e) {
|
|
||||||
tryToClose(ps);
|
|
||||||
throw new DbException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean containsContact(Connection txn, AuthorId remote,
|
public boolean containsContact(Connection txn, AuthorId remote,
|
||||||
AuthorId local) throws DbException {
|
AuthorId local) throws DbException {
|
||||||
@@ -2172,7 +2144,6 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
if (inKeys.size() < (i + 1) * 3) throw new DbStateException();
|
if (inKeys.size() < (i + 1) * 3) throw new DbStateException();
|
||||||
KeySetId keySetId = new KeySetId(rs.getInt(1));
|
KeySetId keySetId = new KeySetId(rs.getInt(1));
|
||||||
ContactId contactId = new ContactId(rs.getInt(2));
|
ContactId contactId = new ContactId(rs.getInt(2));
|
||||||
if (rs.wasNull()) contactId = null;
|
|
||||||
long rotationPeriod = rs.getLong(3);
|
long rotationPeriod = rs.getLong(3);
|
||||||
SecretKey tagKey = new SecretKey(rs.getBytes(4));
|
SecretKey tagKey = new SecretKey(rs.getBytes(4));
|
||||||
SecretKey headerKey = new SecretKey(rs.getBytes(5));
|
SecretKey headerKey = new SecretKey(rs.getBytes(5));
|
||||||
|
|||||||
@@ -0,0 +1,55 @@
|
|||||||
|
package org.briarproject.bramble.db;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.db.DbException;
|
||||||
|
|
||||||
|
import java.sql.Connection;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.sql.Statement;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
import static java.util.logging.Level.WARNING;
|
||||||
|
import static org.briarproject.bramble.util.LogUtils.logException;
|
||||||
|
|
||||||
|
class Migration38_39 implements Migration<Connection> {
|
||||||
|
|
||||||
|
private static final Logger LOG =
|
||||||
|
Logger.getLogger(Migration38_39.class.getName());
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getStartVersion() {
|
||||||
|
return 38;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getEndVersion() {
|
||||||
|
return 39;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void migrate(Connection txn) throws DbException {
|
||||||
|
Statement s = null;
|
||||||
|
try {
|
||||||
|
s = txn.createStatement();
|
||||||
|
// Add not null constraints
|
||||||
|
s.execute("ALTER TABLE outgoingKeys"
|
||||||
|
+ " ALTER COLUMN contactId"
|
||||||
|
+ " SET NOT NULL");
|
||||||
|
s.execute("ALTER TABLE incomingKeys"
|
||||||
|
+ " ALTER COLUMN contactId"
|
||||||
|
+ " SET NOT NULL");
|
||||||
|
} catch (SQLException e) {
|
||||||
|
tryToClose(s);
|
||||||
|
throw new DbException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void tryToClose(@Nullable Statement s) {
|
||||||
|
try {
|
||||||
|
if (s != null) s.close();
|
||||||
|
} catch (SQLException e) {
|
||||||
|
logException(LOG, WARNING, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -31,6 +31,7 @@ import javax.annotation.Nullable;
|
|||||||
import static java.util.logging.Level.INFO;
|
import static java.util.logging.Level.INFO;
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
import static org.briarproject.bramble.api.keyagreement.KeyAgreementConstants.CONNECTION_TIMEOUT;
|
import static org.briarproject.bramble.api.keyagreement.KeyAgreementConstants.CONNECTION_TIMEOUT;
|
||||||
|
import static org.briarproject.bramble.util.LogUtils.logException;
|
||||||
|
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
class KeyAgreementConnector {
|
class KeyAgreementConnector {
|
||||||
@@ -134,7 +135,7 @@ class KeyAgreementConnector {
|
|||||||
Thread.currentThread().interrupt();
|
Thread.currentThread().interrupt();
|
||||||
return null;
|
return null;
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
logException(LOG, WARNING, e);
|
||||||
return null;
|
return null;
|
||||||
} finally {
|
} finally {
|
||||||
stopListening();
|
stopListening();
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ import java.util.logging.Logger;
|
|||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
|
import static org.briarproject.bramble.util.LogUtils.logException;
|
||||||
|
|
||||||
@MethodsNotNullByDefault
|
@MethodsNotNullByDefault
|
||||||
@ParametersNotNullByDefault
|
@ParametersNotNullByDefault
|
||||||
@@ -120,13 +121,11 @@ class KeyAgreementTaskImpl extends Thread implements KeyAgreementTask,
|
|||||||
// Broadcast result to caller
|
// Broadcast result to caller
|
||||||
eventBus.broadcast(new KeyAgreementFinishedEvent(result));
|
eventBus.broadcast(new KeyAgreementFinishedEvent(result));
|
||||||
} catch (AbortException e) {
|
} catch (AbortException e) {
|
||||||
if (LOG.isLoggable(WARNING))
|
logException(LOG, WARNING, e);
|
||||||
LOG.log(WARNING, e.toString(), e);
|
|
||||||
// Notify caller that the protocol was aborted
|
// Notify caller that the protocol was aborted
|
||||||
eventBus.broadcast(new KeyAgreementAbortedEvent(e.receivedAbort));
|
eventBus.broadcast(new KeyAgreementAbortedEvent(e.receivedAbort));
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
if (LOG.isLoggable(WARNING))
|
logException(LOG, WARNING, e);
|
||||||
LOG.log(WARNING, e.toString(), e);
|
|
||||||
// Notify caller that the connection failed
|
// Notify caller that the connection failed
|
||||||
eventBus.broadcast(new KeyAgreementFailedEvent());
|
eventBus.broadcast(new KeyAgreementFailedEvent());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import static org.briarproject.bramble.api.keyagreement.KeyAgreementConstants.PR
|
|||||||
import static org.briarproject.bramble.api.keyagreement.RecordTypes.ABORT;
|
import static org.briarproject.bramble.api.keyagreement.RecordTypes.ABORT;
|
||||||
import static org.briarproject.bramble.api.keyagreement.RecordTypes.CONFIRM;
|
import static org.briarproject.bramble.api.keyagreement.RecordTypes.CONFIRM;
|
||||||
import static org.briarproject.bramble.api.keyagreement.RecordTypes.KEY;
|
import static org.briarproject.bramble.api.keyagreement.RecordTypes.KEY;
|
||||||
|
import static org.briarproject.bramble.util.LogUtils.logException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles the sending and receiving of BQP records.
|
* Handles the sending and receiving of BQP records.
|
||||||
@@ -72,7 +73,7 @@ class KeyAgreementTransport {
|
|||||||
try {
|
try {
|
||||||
writeRecord(ABORT, new byte[0]);
|
writeRecord(ABORT, new byte[0]);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
logException(LOG, WARNING, e);
|
||||||
exception = true;
|
exception = true;
|
||||||
}
|
}
|
||||||
tryToClose(exception);
|
tryToClose(exception);
|
||||||
@@ -83,7 +84,7 @@ class KeyAgreementTransport {
|
|||||||
kac.getConnection().getReader().dispose(exception, true);
|
kac.getConnection().getReader().dispose(exception, true);
|
||||||
kac.getConnection().getWriter().dispose(exception);
|
kac.getConnection().getWriter().dispose(exception);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
logException(LOG, WARNING, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ import javax.annotation.Nullable;
|
|||||||
import javax.annotation.concurrent.ThreadSafe;
|
import javax.annotation.concurrent.ThreadSafe;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import static java.util.logging.Level.FINE;
|
||||||
import static java.util.logging.Level.INFO;
|
import static java.util.logging.Level.INFO;
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.LifecycleState.MIGRATING_DATABASE;
|
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.LifecycleState.MIGRATING_DATABASE;
|
||||||
@@ -43,6 +44,9 @@ import static org.briarproject.bramble.api.lifecycle.LifecycleManager.StartResul
|
|||||||
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.StartResult.DB_ERROR;
|
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.StartResult.DB_ERROR;
|
||||||
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.StartResult.SERVICE_ERROR;
|
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.StartResult.SERVICE_ERROR;
|
||||||
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.StartResult.SUCCESS;
|
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.StartResult.SUCCESS;
|
||||||
|
import static org.briarproject.bramble.util.LogUtils.logDuration;
|
||||||
|
import static org.briarproject.bramble.util.LogUtils.logException;
|
||||||
|
import static org.briarproject.bramble.util.LogUtils.now;
|
||||||
|
|
||||||
@ThreadSafe
|
@ThreadSafe
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
@@ -101,24 +105,20 @@ class LifecycleManagerImpl implements LifecycleManager, MigrationListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private LocalAuthor createLocalAuthor(String nickname) {
|
private LocalAuthor createLocalAuthor(String nickname) {
|
||||||
long now = System.currentTimeMillis();
|
long start = now();
|
||||||
KeyPair keyPair = crypto.generateSignatureKeyPair();
|
KeyPair keyPair = crypto.generateSignatureKeyPair();
|
||||||
byte[] publicKey = keyPair.getPublic().getEncoded();
|
byte[] publicKey = keyPair.getPublic().getEncoded();
|
||||||
byte[] privateKey = keyPair.getPrivate().getEncoded();
|
byte[] privateKey = keyPair.getPrivate().getEncoded();
|
||||||
LocalAuthor localAuthor = authorFactory
|
LocalAuthor localAuthor = authorFactory
|
||||||
.createLocalAuthor(nickname, publicKey, privateKey);
|
.createLocalAuthor(nickname, publicKey, privateKey);
|
||||||
long duration = System.currentTimeMillis() - now;
|
logDuration(LOG, "Creating local author", start);
|
||||||
if (LOG.isLoggable(INFO))
|
|
||||||
LOG.info("Creating local author took " + duration + " ms");
|
|
||||||
return localAuthor;
|
return localAuthor;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void registerLocalAuthor(LocalAuthor author) throws DbException {
|
private void registerLocalAuthor(LocalAuthor author) throws DbException {
|
||||||
long now = System.currentTimeMillis();
|
long start = now();
|
||||||
identityManager.registerLocalAuthor(author);
|
identityManager.registerLocalAuthor(author);
|
||||||
long duration = System.currentTimeMillis() - now;
|
logDuration(LOG, "Registering local author", start);
|
||||||
if (LOG.isLoggable(INFO))
|
|
||||||
LOG.info("Registering local author took " + duration + " ms");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -129,15 +129,11 @@ class LifecycleManagerImpl implements LifecycleManager, MigrationListener {
|
|||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
LOG.info("Starting services");
|
LOG.info("Starting services");
|
||||||
long start = System.currentTimeMillis();
|
long start = now();
|
||||||
|
|
||||||
boolean reopened = db.open(this);
|
boolean reopened = db.open(this);
|
||||||
long duration = System.currentTimeMillis() - start;
|
if (reopened) logDuration(LOG, "Reopening database", start);
|
||||||
if (LOG.isLoggable(INFO)) {
|
else logDuration(LOG, "Creating database", start);
|
||||||
if (reopened)
|
|
||||||
LOG.info("Reopening database took " + duration + " ms");
|
|
||||||
else LOG.info("Creating database took " + duration + " ms");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nickname != null) {
|
if (nickname != null) {
|
||||||
registerLocalAuthor(createLocalAuthor(nickname));
|
registerLocalAuthor(createLocalAuthor(nickname));
|
||||||
@@ -150,13 +146,11 @@ class LifecycleManagerImpl implements LifecycleManager, MigrationListener {
|
|||||||
Transaction txn = db.startTransaction(false);
|
Transaction txn = db.startTransaction(false);
|
||||||
try {
|
try {
|
||||||
for (Client c : clients) {
|
for (Client c : clients) {
|
||||||
start = System.currentTimeMillis();
|
start = now();
|
||||||
c.createLocalState(txn);
|
c.createLocalState(txn);
|
||||||
duration = System.currentTimeMillis() - start;
|
if (LOG.isLoggable(FINE)) {
|
||||||
if (LOG.isLoggable(INFO)) {
|
logDuration(LOG, "Starting client "
|
||||||
LOG.info("Starting client "
|
+ c.getClass().getSimpleName(), start);
|
||||||
+ c.getClass().getSimpleName()
|
|
||||||
+ " took " + duration + " ms");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
db.commitTransaction(txn);
|
db.commitTransaction(txn);
|
||||||
@@ -164,12 +158,11 @@ class LifecycleManagerImpl implements LifecycleManager, MigrationListener {
|
|||||||
db.endTransaction(txn);
|
db.endTransaction(txn);
|
||||||
}
|
}
|
||||||
for (Service s : services) {
|
for (Service s : services) {
|
||||||
start = System.currentTimeMillis();
|
start = now();
|
||||||
s.startService();
|
s.startService();
|
||||||
duration = System.currentTimeMillis() - start;
|
if (LOG.isLoggable(FINE)) {
|
||||||
if (LOG.isLoggable(INFO)) {
|
logDuration(LOG, "Starting service "
|
||||||
LOG.info("Starting service " + s.getClass().getSimpleName()
|
+ s.getClass().getSimpleName(), start);
|
||||||
+ " took " + duration + " ms");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -178,16 +171,16 @@ class LifecycleManagerImpl implements LifecycleManager, MigrationListener {
|
|||||||
eventBus.broadcast(new LifecycleEvent(RUNNING));
|
eventBus.broadcast(new LifecycleEvent(RUNNING));
|
||||||
return SUCCESS;
|
return SUCCESS;
|
||||||
} catch (DataTooOldException e) {
|
} catch (DataTooOldException e) {
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
logException(LOG, WARNING, e);
|
||||||
return DATA_TOO_OLD_ERROR;
|
return DATA_TOO_OLD_ERROR;
|
||||||
} catch (DataTooNewException e) {
|
} catch (DataTooNewException e) {
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
logException(LOG, WARNING, e);
|
||||||
return DATA_TOO_NEW_ERROR;
|
return DATA_TOO_NEW_ERROR;
|
||||||
} catch (DbException e) {
|
} catch (DbException e) {
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
logException(LOG, WARNING, e);
|
||||||
return DB_ERROR;
|
return DB_ERROR;
|
||||||
} catch (ServiceException e) {
|
} catch (ServiceException e) {
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
logException(LOG, WARNING, e);
|
||||||
return SERVICE_ERROR;
|
return SERVICE_ERROR;
|
||||||
} finally {
|
} finally {
|
||||||
startStopSemaphore.release();
|
startStopSemaphore.release();
|
||||||
@@ -213,29 +206,26 @@ class LifecycleManagerImpl implements LifecycleManager, MigrationListener {
|
|||||||
state = STOPPING;
|
state = STOPPING;
|
||||||
eventBus.broadcast(new LifecycleEvent(STOPPING));
|
eventBus.broadcast(new LifecycleEvent(STOPPING));
|
||||||
for (Service s : services) {
|
for (Service s : services) {
|
||||||
long start = System.currentTimeMillis();
|
long start = now();
|
||||||
s.stopService();
|
s.stopService();
|
||||||
long duration = System.currentTimeMillis() - start;
|
if (LOG.isLoggable(FINE)) {
|
||||||
if (LOG.isLoggable(INFO)) {
|
logDuration(LOG, "Stopping service "
|
||||||
LOG.info("Stopping service " + s.getClass().getSimpleName()
|
+ s.getClass().getSimpleName(), start);
|
||||||
+ " took " + duration + " ms");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (ExecutorService e : executors) {
|
for (ExecutorService e : executors) {
|
||||||
if (LOG.isLoggable(INFO)) {
|
if (LOG.isLoggable(FINE)) {
|
||||||
LOG.info("Stopping executor "
|
LOG.fine("Stopping executor "
|
||||||
+ e.getClass().getSimpleName());
|
+ e.getClass().getSimpleName());
|
||||||
}
|
}
|
||||||
e.shutdownNow();
|
e.shutdownNow();
|
||||||
}
|
}
|
||||||
long start = System.currentTimeMillis();
|
long start = now();
|
||||||
db.close();
|
db.close();
|
||||||
long duration = System.currentTimeMillis() - start;
|
logDuration(LOG, "Closing database", start);
|
||||||
if (LOG.isLoggable(INFO))
|
|
||||||
LOG.info("Closing database took " + duration + " ms");
|
|
||||||
shutdownLatch.countDown();
|
shutdownLatch.countDown();
|
||||||
} catch (DbException | ServiceException e) {
|
} catch (DbException | ServiceException e) {
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
logException(LOG, WARNING, e);
|
||||||
} finally {
|
} finally {
|
||||||
startStopSemaphore.release();
|
startStopSemaphore.release();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ import javax.inject.Inject;
|
|||||||
|
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
import static org.briarproject.bramble.api.transport.TransportConstants.TAG_LENGTH;
|
import static org.briarproject.bramble.api.transport.TransportConstants.TAG_LENGTH;
|
||||||
|
import static org.briarproject.bramble.util.LogUtils.logException;
|
||||||
|
|
||||||
class ConnectionManagerImpl implements ConnectionManager {
|
class ConnectionManagerImpl implements ConnectionManager {
|
||||||
|
|
||||||
@@ -135,7 +136,7 @@ class ConnectionManagerImpl implements ConnectionManager {
|
|||||||
byte[] tag = readTag(reader);
|
byte[] tag = readTag(reader);
|
||||||
ctx = keyManager.getStreamContext(transportId, tag);
|
ctx = keyManager.getStreamContext(transportId, tag);
|
||||||
} catch (IOException | DbException e) {
|
} catch (IOException | DbException e) {
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
logException(LOG, WARNING, e);
|
||||||
disposeReader(true, false);
|
disposeReader(true, false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -151,7 +152,7 @@ class ConnectionManagerImpl implements ConnectionManager {
|
|||||||
createIncomingSession(ctx, reader).run();
|
createIncomingSession(ctx, reader).run();
|
||||||
disposeReader(false, true);
|
disposeReader(false, true);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
logException(LOG, WARNING, e);
|
||||||
disposeReader(true, true);
|
disposeReader(true, true);
|
||||||
} finally {
|
} finally {
|
||||||
connectionRegistry.unregisterConnection(contactId, transportId,
|
connectionRegistry.unregisterConnection(contactId, transportId,
|
||||||
@@ -163,7 +164,7 @@ class ConnectionManagerImpl implements ConnectionManager {
|
|||||||
try {
|
try {
|
||||||
reader.dispose(exception, recognised);
|
reader.dispose(exception, recognised);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
logException(LOG, WARNING, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -188,7 +189,7 @@ class ConnectionManagerImpl implements ConnectionManager {
|
|||||||
try {
|
try {
|
||||||
ctx = keyManager.getStreamContext(contactId, transportId);
|
ctx = keyManager.getStreamContext(contactId, transportId);
|
||||||
} catch (DbException e) {
|
} catch (DbException e) {
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
logException(LOG, WARNING, e);
|
||||||
disposeWriter(true);
|
disposeWriter(true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -204,7 +205,7 @@ class ConnectionManagerImpl implements ConnectionManager {
|
|||||||
createSimplexOutgoingSession(ctx, writer).run();
|
createSimplexOutgoingSession(ctx, writer).run();
|
||||||
disposeWriter(false);
|
disposeWriter(false);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
logException(LOG, WARNING, e);
|
||||||
disposeWriter(true);
|
disposeWriter(true);
|
||||||
} finally {
|
} finally {
|
||||||
connectionRegistry.unregisterConnection(contactId, transportId,
|
connectionRegistry.unregisterConnection(contactId, transportId,
|
||||||
@@ -216,7 +217,7 @@ class ConnectionManagerImpl implements ConnectionManager {
|
|||||||
try {
|
try {
|
||||||
writer.dispose(exception);
|
writer.dispose(exception);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
logException(LOG, WARNING, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -246,7 +247,7 @@ class ConnectionManagerImpl implements ConnectionManager {
|
|||||||
byte[] tag = readTag(reader);
|
byte[] tag = readTag(reader);
|
||||||
ctx = keyManager.getStreamContext(transportId, tag);
|
ctx = keyManager.getStreamContext(transportId, tag);
|
||||||
} catch (IOException | DbException e) {
|
} catch (IOException | DbException e) {
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
logException(LOG, WARNING, e);
|
||||||
disposeReader(true, false);
|
disposeReader(true, false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -265,7 +266,7 @@ class ConnectionManagerImpl implements ConnectionManager {
|
|||||||
incomingSession.run();
|
incomingSession.run();
|
||||||
disposeReader(false, true);
|
disposeReader(false, true);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
logException(LOG, WARNING, e);
|
||||||
disposeReader(true, true);
|
disposeReader(true, true);
|
||||||
} finally {
|
} finally {
|
||||||
connectionRegistry.unregisterConnection(contactId, transportId,
|
connectionRegistry.unregisterConnection(contactId, transportId,
|
||||||
@@ -279,7 +280,7 @@ class ConnectionManagerImpl implements ConnectionManager {
|
|||||||
try {
|
try {
|
||||||
ctx = keyManager.getStreamContext(contactId, transportId);
|
ctx = keyManager.getStreamContext(contactId, transportId);
|
||||||
} catch (DbException e) {
|
} catch (DbException e) {
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
logException(LOG, WARNING, e);
|
||||||
disposeWriter(true);
|
disposeWriter(true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -294,7 +295,7 @@ class ConnectionManagerImpl implements ConnectionManager {
|
|||||||
outgoingSession.run();
|
outgoingSession.run();
|
||||||
disposeWriter(false);
|
disposeWriter(false);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
logException(LOG, WARNING, e);
|
||||||
disposeWriter(true);
|
disposeWriter(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -305,7 +306,7 @@ class ConnectionManagerImpl implements ConnectionManager {
|
|||||||
try {
|
try {
|
||||||
reader.dispose(exception, recognised);
|
reader.dispose(exception, recognised);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
logException(LOG, WARNING, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -317,7 +318,7 @@ class ConnectionManagerImpl implements ConnectionManager {
|
|||||||
try {
|
try {
|
||||||
writer.dispose(exception);
|
writer.dispose(exception);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
logException(LOG, WARNING, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -347,7 +348,7 @@ class ConnectionManagerImpl implements ConnectionManager {
|
|||||||
try {
|
try {
|
||||||
ctx = keyManager.getStreamContext(contactId, transportId);
|
ctx = keyManager.getStreamContext(contactId, transportId);
|
||||||
} catch (DbException e) {
|
} catch (DbException e) {
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
logException(LOG, WARNING, e);
|
||||||
disposeWriter(true);
|
disposeWriter(true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -364,7 +365,7 @@ class ConnectionManagerImpl implements ConnectionManager {
|
|||||||
outgoingSession.run();
|
outgoingSession.run();
|
||||||
disposeWriter(false);
|
disposeWriter(false);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
logException(LOG, WARNING, e);
|
||||||
disposeWriter(true);
|
disposeWriter(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -376,7 +377,7 @@ class ConnectionManagerImpl implements ConnectionManager {
|
|||||||
byte[] tag = readTag(reader);
|
byte[] tag = readTag(reader);
|
||||||
ctx = keyManager.getStreamContext(transportId, tag);
|
ctx = keyManager.getStreamContext(transportId, tag);
|
||||||
} catch (IOException | DbException e) {
|
} catch (IOException | DbException e) {
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
logException(LOG, WARNING, e);
|
||||||
disposeReader(true, false);
|
disposeReader(true, false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -400,7 +401,7 @@ class ConnectionManagerImpl implements ConnectionManager {
|
|||||||
incomingSession.run();
|
incomingSession.run();
|
||||||
disposeReader(false, true);
|
disposeReader(false, true);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
logException(LOG, WARNING, e);
|
||||||
disposeReader(true, true);
|
disposeReader(true, true);
|
||||||
} finally {
|
} finally {
|
||||||
connectionRegistry.unregisterConnection(contactId, transportId,
|
connectionRegistry.unregisterConnection(contactId, transportId,
|
||||||
@@ -414,7 +415,7 @@ class ConnectionManagerImpl implements ConnectionManager {
|
|||||||
try {
|
try {
|
||||||
reader.dispose(exception, recognised);
|
reader.dispose(exception, recognised);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
logException(LOG, WARNING, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -426,7 +427,7 @@ class ConnectionManagerImpl implements ConnectionManager {
|
|||||||
try {
|
try {
|
||||||
writer.dispose(exception);
|
writer.dispose(exception);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
logException(LOG, WARNING, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import org.briarproject.bramble.api.lifecycle.Service;
|
|||||||
import org.briarproject.bramble.api.lifecycle.ServiceException;
|
import org.briarproject.bramble.api.lifecycle.ServiceException;
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
import org.briarproject.bramble.api.plugin.ConnectionManager;
|
import org.briarproject.bramble.api.plugin.ConnectionManager;
|
||||||
|
import org.briarproject.bramble.api.plugin.ConnectionRegistry;
|
||||||
import org.briarproject.bramble.api.plugin.Plugin;
|
import org.briarproject.bramble.api.plugin.Plugin;
|
||||||
import org.briarproject.bramble.api.plugin.PluginCallback;
|
import org.briarproject.bramble.api.plugin.PluginCallback;
|
||||||
import org.briarproject.bramble.api.plugin.PluginConfig;
|
import org.briarproject.bramble.api.plugin.PluginConfig;
|
||||||
@@ -29,25 +30,31 @@ import org.briarproject.bramble.api.properties.TransportProperties;
|
|||||||
import org.briarproject.bramble.api.properties.TransportPropertyManager;
|
import org.briarproject.bramble.api.properties.TransportPropertyManager;
|
||||||
import org.briarproject.bramble.api.settings.Settings;
|
import org.briarproject.bramble.api.settings.Settings;
|
||||||
import org.briarproject.bramble.api.settings.SettingsManager;
|
import org.briarproject.bramble.api.settings.SettingsManager;
|
||||||
import org.briarproject.bramble.api.ui.UiCallback;
|
import org.briarproject.bramble.api.system.Clock;
|
||||||
|
import org.briarproject.bramble.api.system.Scheduler;
|
||||||
|
|
||||||
|
import java.security.SecureRandom;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.concurrent.CopyOnWriteArrayList;
|
import java.util.concurrent.CopyOnWriteArrayList;
|
||||||
import java.util.concurrent.CountDownLatch;
|
import java.util.concurrent.CountDownLatch;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import javax.annotation.concurrent.ThreadSafe;
|
import javax.annotation.concurrent.ThreadSafe;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import static java.util.logging.Level.FINE;
|
||||||
import static java.util.logging.Level.INFO;
|
import static java.util.logging.Level.INFO;
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
|
import static org.briarproject.bramble.util.LogUtils.logDuration;
|
||||||
|
import static org.briarproject.bramble.util.LogUtils.logException;
|
||||||
|
import static org.briarproject.bramble.util.LogUtils.now;
|
||||||
|
|
||||||
@ThreadSafe
|
@ThreadSafe
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
@@ -57,12 +64,15 @@ class PluginManagerImpl implements PluginManager, Service {
|
|||||||
Logger.getLogger(PluginManagerImpl.class.getName());
|
Logger.getLogger(PluginManagerImpl.class.getName());
|
||||||
|
|
||||||
private final Executor ioExecutor;
|
private final Executor ioExecutor;
|
||||||
|
private final ScheduledExecutorService scheduler;
|
||||||
private final EventBus eventBus;
|
private final EventBus eventBus;
|
||||||
private final PluginConfig pluginConfig;
|
private final PluginConfig pluginConfig;
|
||||||
private final ConnectionManager connectionManager;
|
private final ConnectionManager connectionManager;
|
||||||
|
private final ConnectionRegistry connectionRegistry;
|
||||||
private final SettingsManager settingsManager;
|
private final SettingsManager settingsManager;
|
||||||
private final TransportPropertyManager transportPropertyManager;
|
private final TransportPropertyManager transportPropertyManager;
|
||||||
private final UiCallback uiCallback;
|
private final SecureRandom random;
|
||||||
|
private final Clock clock;
|
||||||
private final Map<TransportId, Plugin> plugins;
|
private final Map<TransportId, Plugin> plugins;
|
||||||
private final List<SimplexPlugin> simplexPlugins;
|
private final List<SimplexPlugin> simplexPlugins;
|
||||||
private final List<DuplexPlugin> duplexPlugins;
|
private final List<DuplexPlugin> duplexPlugins;
|
||||||
@@ -70,27 +80,41 @@ class PluginManagerImpl implements PluginManager, Service {
|
|||||||
private final AtomicBoolean used = new AtomicBoolean(false);
|
private final AtomicBoolean used = new AtomicBoolean(false);
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
PluginManagerImpl(@IoExecutor Executor ioExecutor, EventBus eventBus,
|
PluginManagerImpl(@IoExecutor Executor ioExecutor,
|
||||||
|
@Scheduler ScheduledExecutorService scheduler, EventBus eventBus,
|
||||||
PluginConfig pluginConfig, ConnectionManager connectionManager,
|
PluginConfig pluginConfig, ConnectionManager connectionManager,
|
||||||
|
ConnectionRegistry connectionRegistry,
|
||||||
SettingsManager settingsManager,
|
SettingsManager settingsManager,
|
||||||
TransportPropertyManager transportPropertyManager,
|
TransportPropertyManager transportPropertyManager,
|
||||||
UiCallback uiCallback) {
|
SecureRandom random, Clock clock) {
|
||||||
this.ioExecutor = ioExecutor;
|
this.ioExecutor = ioExecutor;
|
||||||
|
this.scheduler = scheduler;
|
||||||
this.eventBus = eventBus;
|
this.eventBus = eventBus;
|
||||||
this.pluginConfig = pluginConfig;
|
this.pluginConfig = pluginConfig;
|
||||||
this.connectionManager = connectionManager;
|
this.connectionManager = connectionManager;
|
||||||
|
this.connectionRegistry = connectionRegistry;
|
||||||
this.settingsManager = settingsManager;
|
this.settingsManager = settingsManager;
|
||||||
this.transportPropertyManager = transportPropertyManager;
|
this.transportPropertyManager = transportPropertyManager;
|
||||||
this.uiCallback = uiCallback;
|
this.random = random;
|
||||||
|
this.clock = clock;
|
||||||
plugins = new ConcurrentHashMap<>();
|
plugins = new ConcurrentHashMap<>();
|
||||||
simplexPlugins = new CopyOnWriteArrayList<>();
|
simplexPlugins = new CopyOnWriteArrayList<>();
|
||||||
duplexPlugins = new CopyOnWriteArrayList<>();
|
duplexPlugins = new CopyOnWriteArrayList<>();
|
||||||
startLatches = new ConcurrentHashMap<>();
|
startLatches = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void startService() throws ServiceException {
|
public void startService() {
|
||||||
if (used.getAndSet(true)) throw new IllegalStateException();
|
if (used.getAndSet(true)) throw new IllegalStateException();
|
||||||
|
// Instantiate the poller
|
||||||
|
if (pluginConfig.shouldPoll()) {
|
||||||
|
LOG.info("Starting poller");
|
||||||
|
Poller poller = new Poller(ioExecutor, scheduler, connectionManager,
|
||||||
|
connectionRegistry, this, transportPropertyManager, random,
|
||||||
|
clock);
|
||||||
|
eventBus.addListener(poller);
|
||||||
|
}
|
||||||
// Instantiate the simplex plugins and start them asynchronously
|
// Instantiate the simplex plugins and start them asynchronously
|
||||||
LOG.info("Starting simplex plugins");
|
LOG.info("Starting simplex plugins");
|
||||||
for (SimplexPluginFactory f : pluginConfig.getSimplexFactories()) {
|
for (SimplexPluginFactory f : pluginConfig.getSimplexFactories()) {
|
||||||
@@ -185,17 +209,16 @@ class PluginManagerImpl implements PluginManager, Service {
|
|||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
long start = System.currentTimeMillis();
|
long start = now();
|
||||||
plugin.start();
|
plugin.start();
|
||||||
long duration = System.currentTimeMillis() - start;
|
if (LOG.isLoggable(FINE)) {
|
||||||
if (LOG.isLoggable(INFO)) {
|
logDuration(LOG, "Starting plugin " + plugin.getId(),
|
||||||
LOG.info("Starting plugin " + plugin.getId() + " took " +
|
start);
|
||||||
duration + " ms");
|
|
||||||
}
|
}
|
||||||
} catch (PluginException e) {
|
} catch (PluginException e) {
|
||||||
if (LOG.isLoggable(WARNING)) {
|
if (LOG.isLoggable(WARNING)) {
|
||||||
LOG.warning("Plugin " + plugin.getId() + " did not start");
|
LOG.warning("Plugin " + plugin.getId() + " did not start");
|
||||||
LOG.log(WARNING, e.toString(), e);
|
logException(LOG, WARNING, e);
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
startLatch.countDown();
|
startLatch.countDown();
|
||||||
@@ -223,12 +246,11 @@ class PluginManagerImpl implements PluginManager, Service {
|
|||||||
// Wait for the plugin to finish starting
|
// Wait for the plugin to finish starting
|
||||||
startLatch.await();
|
startLatch.await();
|
||||||
// Stop the plugin
|
// Stop the plugin
|
||||||
long start = System.currentTimeMillis();
|
long start = now();
|
||||||
plugin.stop();
|
plugin.stop();
|
||||||
long duration = System.currentTimeMillis() - start;
|
if (LOG.isLoggable(FINE)) {
|
||||||
if (LOG.isLoggable(INFO)) {
|
logDuration(LOG, "Stopping plugin " + plugin.getId(),
|
||||||
LOG.info("Stopping plugin " + plugin.getId()
|
start);
|
||||||
+ " took " + duration + " ms");
|
|
||||||
}
|
}
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
LOG.warning("Interrupted while waiting for plugin to stop");
|
LOG.warning("Interrupted while waiting for plugin to stop");
|
||||||
@@ -236,7 +258,7 @@ class PluginManagerImpl implements PluginManager, Service {
|
|||||||
} catch (PluginException e) {
|
} catch (PluginException e) {
|
||||||
if (LOG.isLoggable(WARNING)) {
|
if (LOG.isLoggable(WARNING)) {
|
||||||
LOG.warning("Plugin " + plugin.getId() + " did not stop");
|
LOG.warning("Plugin " + plugin.getId() + " did not stop");
|
||||||
LOG.log(WARNING, e.toString(), e);
|
logException(LOG, WARNING, e);
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
stopLatch.countDown();
|
stopLatch.countDown();
|
||||||
@@ -258,7 +280,7 @@ class PluginManagerImpl implements PluginManager, Service {
|
|||||||
try {
|
try {
|
||||||
return settingsManager.getSettings(id.getString());
|
return settingsManager.getSettings(id.getString());
|
||||||
} catch (DbException e) {
|
} catch (DbException e) {
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
logException(LOG, WARNING, e);
|
||||||
return new Settings();
|
return new Settings();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -268,27 +290,7 @@ class PluginManagerImpl implements PluginManager, Service {
|
|||||||
try {
|
try {
|
||||||
return transportPropertyManager.getLocalProperties(id);
|
return transportPropertyManager.getLocalProperties(id);
|
||||||
} catch (DbException e) {
|
} catch (DbException e) {
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
logException(LOG, WARNING, e);
|
||||||
return new TransportProperties();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Map<ContactId, TransportProperties> getRemoteProperties() {
|
|
||||||
try {
|
|
||||||
return transportPropertyManager.getRemoteProperties(id);
|
|
||||||
} catch (DbException e) {
|
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
|
||||||
return Collections.emptyMap();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public TransportProperties getRemoteProperties(ContactId c) {
|
|
||||||
try {
|
|
||||||
return transportPropertyManager.getRemoteProperties(c, id);
|
|
||||||
} catch (DbException e) {
|
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
|
||||||
return new TransportProperties();
|
return new TransportProperties();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -298,7 +300,7 @@ class PluginManagerImpl implements PluginManager, Service {
|
|||||||
try {
|
try {
|
||||||
settingsManager.mergeSettings(s, id.getString());
|
settingsManager.mergeSettings(s, id.getString());
|
||||||
} catch (DbException e) {
|
} catch (DbException e) {
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
logException(LOG, WARNING, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -307,25 +309,10 @@ class PluginManagerImpl implements PluginManager, Service {
|
|||||||
try {
|
try {
|
||||||
transportPropertyManager.mergeLocalProperties(id, p);
|
transportPropertyManager.mergeLocalProperties(id, p);
|
||||||
} catch (DbException e) {
|
} catch (DbException e) {
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
logException(LOG, WARNING, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public int showChoice(String[] options, String... message) {
|
|
||||||
return uiCallback.showChoice(options, message);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean showConfirmationMessage(String... message) {
|
|
||||||
return uiCallback.showConfirmationMessage(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void showMessage(String... message) {
|
|
||||||
uiCallback.showMessage(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void transportEnabled() {
|
public void transportEnabled() {
|
||||||
eventBus.broadcast(new TransportEnabledEvent(id));
|
eventBus.broadcast(new TransportEnabledEvent(id));
|
||||||
|
|||||||
@@ -1,18 +1,10 @@
|
|||||||
package org.briarproject.bramble.plugin;
|
package org.briarproject.bramble.plugin;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.event.EventBus;
|
|
||||||
import org.briarproject.bramble.api.lifecycle.IoExecutor;
|
|
||||||
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
|
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
|
||||||
import org.briarproject.bramble.api.plugin.BackoffFactory;
|
import org.briarproject.bramble.api.plugin.BackoffFactory;
|
||||||
import org.briarproject.bramble.api.plugin.ConnectionManager;
|
import org.briarproject.bramble.api.plugin.ConnectionManager;
|
||||||
import org.briarproject.bramble.api.plugin.ConnectionRegistry;
|
import org.briarproject.bramble.api.plugin.ConnectionRegistry;
|
||||||
import org.briarproject.bramble.api.plugin.PluginManager;
|
import org.briarproject.bramble.api.plugin.PluginManager;
|
||||||
import org.briarproject.bramble.api.system.Clock;
|
|
||||||
import org.briarproject.bramble.api.system.Scheduler;
|
|
||||||
|
|
||||||
import java.security.SecureRandom;
|
|
||||||
import java.util.concurrent.Executor;
|
|
||||||
import java.util.concurrent.ScheduledExecutorService;
|
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javax.inject.Singleton;
|
import javax.inject.Singleton;
|
||||||
@@ -26,8 +18,6 @@ public class PluginModule {
|
|||||||
public static class EagerSingletons {
|
public static class EagerSingletons {
|
||||||
@Inject
|
@Inject
|
||||||
PluginManager pluginManager;
|
PluginManager pluginManager;
|
||||||
@Inject
|
|
||||||
Poller poller;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@@ -35,19 +25,6 @@ public class PluginModule {
|
|||||||
return new BackoffFactoryImpl();
|
return new BackoffFactoryImpl();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
|
||||||
@Singleton
|
|
||||||
Poller providePoller(@IoExecutor Executor ioExecutor,
|
|
||||||
@Scheduler ScheduledExecutorService scheduler,
|
|
||||||
ConnectionManager connectionManager,
|
|
||||||
ConnectionRegistry connectionRegistry, PluginManager pluginManager,
|
|
||||||
SecureRandom random, Clock clock, EventBus eventBus) {
|
|
||||||
Poller poller = new Poller(ioExecutor, scheduler, connectionManager,
|
|
||||||
connectionRegistry, pluginManager, random, clock);
|
|
||||||
eventBus.addListener(poller);
|
|
||||||
return poller;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
@Singleton
|
||||||
ConnectionManager provideConnectionManager(
|
ConnectionManager provideConnectionManager(
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package org.briarproject.bramble.plugin;
|
|||||||
|
|
||||||
import org.briarproject.bramble.api.contact.ContactId;
|
import org.briarproject.bramble.api.contact.ContactId;
|
||||||
import org.briarproject.bramble.api.contact.event.ContactStatusChangedEvent;
|
import org.briarproject.bramble.api.contact.event.ContactStatusChangedEvent;
|
||||||
|
import org.briarproject.bramble.api.db.DbException;
|
||||||
import org.briarproject.bramble.api.event.Event;
|
import org.briarproject.bramble.api.event.Event;
|
||||||
import org.briarproject.bramble.api.event.EventListener;
|
import org.briarproject.bramble.api.event.EventListener;
|
||||||
import org.briarproject.bramble.api.lifecycle.IoExecutor;
|
import org.briarproject.bramble.api.lifecycle.IoExecutor;
|
||||||
@@ -19,10 +20,13 @@ import org.briarproject.bramble.api.plugin.event.ConnectionOpenedEvent;
|
|||||||
import org.briarproject.bramble.api.plugin.event.TransportDisabledEvent;
|
import org.briarproject.bramble.api.plugin.event.TransportDisabledEvent;
|
||||||
import org.briarproject.bramble.api.plugin.event.TransportEnabledEvent;
|
import org.briarproject.bramble.api.plugin.event.TransportEnabledEvent;
|
||||||
import org.briarproject.bramble.api.plugin.simplex.SimplexPlugin;
|
import org.briarproject.bramble.api.plugin.simplex.SimplexPlugin;
|
||||||
|
import org.briarproject.bramble.api.properties.TransportProperties;
|
||||||
|
import org.briarproject.bramble.api.properties.TransportPropertyManager;
|
||||||
import org.briarproject.bramble.api.system.Clock;
|
import org.briarproject.bramble.api.system.Clock;
|
||||||
import org.briarproject.bramble.api.system.Scheduler;
|
import org.briarproject.bramble.api.system.Scheduler;
|
||||||
|
|
||||||
import java.security.SecureRandom;
|
import java.security.SecureRandom;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
@@ -33,10 +37,11 @@ import java.util.concurrent.locks.ReentrantLock;
|
|||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import javax.annotation.concurrent.ThreadSafe;
|
import javax.annotation.concurrent.ThreadSafe;
|
||||||
import javax.inject.Inject;
|
|
||||||
|
|
||||||
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
||||||
import static java.util.logging.Level.INFO;
|
import static java.util.logging.Level.INFO;
|
||||||
|
import static java.util.logging.Level.WARNING;
|
||||||
|
import static org.briarproject.bramble.util.LogUtils.logException;
|
||||||
|
|
||||||
@ThreadSafe
|
@ThreadSafe
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
@@ -49,22 +54,24 @@ class Poller implements EventListener {
|
|||||||
private final ConnectionManager connectionManager;
|
private final ConnectionManager connectionManager;
|
||||||
private final ConnectionRegistry connectionRegistry;
|
private final ConnectionRegistry connectionRegistry;
|
||||||
private final PluginManager pluginManager;
|
private final PluginManager pluginManager;
|
||||||
|
private final TransportPropertyManager transportPropertyManager;
|
||||||
private final SecureRandom random;
|
private final SecureRandom random;
|
||||||
private final Clock clock;
|
private final Clock clock;
|
||||||
private final Lock lock;
|
private final Lock lock;
|
||||||
private final Map<TransportId, ScheduledPollTask> tasks; // Locking: lock
|
private final Map<TransportId, ScheduledPollTask> tasks; // Locking: lock
|
||||||
|
|
||||||
@Inject
|
|
||||||
Poller(@IoExecutor Executor ioExecutor,
|
Poller(@IoExecutor Executor ioExecutor,
|
||||||
@Scheduler ScheduledExecutorService scheduler,
|
@Scheduler ScheduledExecutorService scheduler,
|
||||||
ConnectionManager connectionManager,
|
ConnectionManager connectionManager,
|
||||||
ConnectionRegistry connectionRegistry, PluginManager pluginManager,
|
ConnectionRegistry connectionRegistry, PluginManager pluginManager,
|
||||||
|
TransportPropertyManager transportPropertyManager,
|
||||||
SecureRandom random, Clock clock) {
|
SecureRandom random, Clock clock) {
|
||||||
this.ioExecutor = ioExecutor;
|
this.ioExecutor = ioExecutor;
|
||||||
this.scheduler = scheduler;
|
this.scheduler = scheduler;
|
||||||
this.connectionManager = connectionManager;
|
this.connectionManager = connectionManager;
|
||||||
this.connectionRegistry = connectionRegistry;
|
this.connectionRegistry = connectionRegistry;
|
||||||
this.pluginManager = pluginManager;
|
this.pluginManager = pluginManager;
|
||||||
|
this.transportPropertyManager = transportPropertyManager;
|
||||||
this.random = random;
|
this.random = random;
|
||||||
this.clock = clock;
|
this.clock = clock;
|
||||||
lock = new ReentrantLock();
|
lock = new ReentrantLock();
|
||||||
@@ -120,10 +127,15 @@ class Poller implements EventListener {
|
|||||||
private void connectToContact(ContactId c, SimplexPlugin p) {
|
private void connectToContact(ContactId c, SimplexPlugin p) {
|
||||||
ioExecutor.execute(() -> {
|
ioExecutor.execute(() -> {
|
||||||
TransportId t = p.getId();
|
TransportId t = p.getId();
|
||||||
if (!connectionRegistry.isConnected(c, t)) {
|
if (connectionRegistry.isConnected(c, t)) return;
|
||||||
TransportConnectionWriter w = p.createWriter(c);
|
try {
|
||||||
|
TransportProperties props =
|
||||||
|
transportPropertyManager.getRemoteProperties(c, t);
|
||||||
|
TransportConnectionWriter w = p.createWriter(props);
|
||||||
if (w != null)
|
if (w != null)
|
||||||
connectionManager.manageOutgoingConnection(c, t, w);
|
connectionManager.manageOutgoingConnection(c, t, w);
|
||||||
|
} catch (DbException e) {
|
||||||
|
logException(LOG, WARNING, e);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -131,10 +143,15 @@ class Poller implements EventListener {
|
|||||||
private void connectToContact(ContactId c, DuplexPlugin p) {
|
private void connectToContact(ContactId c, DuplexPlugin p) {
|
||||||
ioExecutor.execute(() -> {
|
ioExecutor.execute(() -> {
|
||||||
TransportId t = p.getId();
|
TransportId t = p.getId();
|
||||||
if (!connectionRegistry.isConnected(c, t)) {
|
if (connectionRegistry.isConnected(c, t)) return;
|
||||||
DuplexTransportConnection d = p.createConnection(c);
|
try {
|
||||||
|
TransportProperties props =
|
||||||
|
transportPropertyManager.getRemoteProperties(c, t);
|
||||||
|
DuplexTransportConnection d = p.createConnection(props);
|
||||||
if (d != null)
|
if (d != null)
|
||||||
connectionManager.manageOutgoingConnection(c, t, d);
|
connectionManager.manageOutgoingConnection(c, t, d);
|
||||||
|
} catch (DbException e) {
|
||||||
|
logException(LOG, WARNING, e);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -186,7 +203,17 @@ class Poller implements EventListener {
|
|||||||
private void poll(Plugin p) {
|
private void poll(Plugin p) {
|
||||||
TransportId t = p.getId();
|
TransportId t = p.getId();
|
||||||
if (LOG.isLoggable(INFO)) LOG.info("Polling plugin " + t);
|
if (LOG.isLoggable(INFO)) LOG.info("Polling plugin " + t);
|
||||||
p.poll(connectionRegistry.getConnectedContacts(t));
|
try {
|
||||||
|
Map<ContactId, TransportProperties> remote =
|
||||||
|
transportPropertyManager.getRemoteProperties(t);
|
||||||
|
Collection<ContactId> connected =
|
||||||
|
connectionRegistry.getConnectedContacts(t);
|
||||||
|
remote = new HashMap<>(remote);
|
||||||
|
remote.keySet().removeAll(connected);
|
||||||
|
if (!remote.isEmpty()) p.poll(remote);
|
||||||
|
} catch (DbException e) {
|
||||||
|
logException(LOG, WARNING, e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ScheduledPollTask {
|
private class ScheduledPollTask {
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import javax.annotation.concurrent.ThreadSafe;
|
|||||||
|
|
||||||
import static java.util.logging.Level.INFO;
|
import static java.util.logging.Level.INFO;
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
|
import static org.briarproject.bramble.util.LogUtils.logException;
|
||||||
|
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
@ThreadSafe
|
@ThreadSafe
|
||||||
@@ -92,7 +93,7 @@ class BluetoothConnectionLimiterImpl implements BluetoothConnectionLimiter {
|
|||||||
conn.getWriter().dispose(false);
|
conn.getWriter().dispose(false);
|
||||||
conn.getReader().dispose(false, false);
|
conn.getReader().dispose(false, false);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
logException(LOG, WARNING, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,6 @@ import org.briarproject.bramble.util.StringUtils;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.security.SecureRandom;
|
import java.security.SecureRandom;
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
@@ -44,6 +43,7 @@ import static org.briarproject.bramble.api.plugin.BluetoothConstants.PREF_BT_ENA
|
|||||||
import static org.briarproject.bramble.api.plugin.BluetoothConstants.PROP_ADDRESS;
|
import static org.briarproject.bramble.api.plugin.BluetoothConstants.PROP_ADDRESS;
|
||||||
import static org.briarproject.bramble.api.plugin.BluetoothConstants.PROP_UUID;
|
import static org.briarproject.bramble.api.plugin.BluetoothConstants.PROP_UUID;
|
||||||
import static org.briarproject.bramble.api.plugin.BluetoothConstants.UUID_BYTES;
|
import static org.briarproject.bramble.api.plugin.BluetoothConstants.UUID_BYTES;
|
||||||
|
import static org.briarproject.bramble.util.LogUtils.logException;
|
||||||
import static org.briarproject.bramble.util.PrivacyUtils.scrubMacAddress;
|
import static org.briarproject.bramble.util.PrivacyUtils.scrubMacAddress;
|
||||||
|
|
||||||
@MethodsNotNullByDefault
|
@MethodsNotNullByDefault
|
||||||
@@ -170,7 +170,7 @@ abstract class BluetoothPlugin<SS> implements DuplexPlugin, EventListener {
|
|||||||
try {
|
try {
|
||||||
ss = openServerSocket(contactConnectionsUuid);
|
ss = openServerSocket(contactConnectionsUuid);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
logException(LOG, WARNING, e);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!isRunning() || !shouldAllowContactConnections()) {
|
if (!isRunning() || !shouldAllowContactConnections()) {
|
||||||
@@ -250,19 +250,16 @@ abstract class BluetoothPlugin<SS> implements DuplexPlugin, EventListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void poll(Collection<ContactId> connected) {
|
public void poll(Map<ContactId, TransportProperties> contacts) {
|
||||||
if (!isRunning() || !shouldAllowContactConnections()) return;
|
if (!isRunning() || !shouldAllowContactConnections()) return;
|
||||||
backoff.increment();
|
backoff.increment();
|
||||||
// Try to connect to known devices in parallel
|
// Try to connect to known devices in parallel
|
||||||
Map<ContactId, TransportProperties> remote =
|
for (Entry<ContactId, TransportProperties> e : contacts.entrySet()) {
|
||||||
callback.getRemoteProperties();
|
|
||||||
for (Entry<ContactId, TransportProperties> e : remote.entrySet()) {
|
|
||||||
ContactId c = e.getKey();
|
|
||||||
if (connected.contains(c)) continue;
|
|
||||||
String address = e.getValue().get(PROP_ADDRESS);
|
String address = e.getValue().get(PROP_ADDRESS);
|
||||||
if (StringUtils.isNullOrEmpty(address)) continue;
|
if (StringUtils.isNullOrEmpty(address)) continue;
|
||||||
String uuid = e.getValue().get(PROP_UUID);
|
String uuid = e.getValue().get(PROP_UUID);
|
||||||
if (StringUtils.isNullOrEmpty(uuid)) continue;
|
if (StringUtils.isNullOrEmpty(uuid)) continue;
|
||||||
|
ContactId c = e.getKey();
|
||||||
ioExecutor.execute(() -> {
|
ioExecutor.execute(() -> {
|
||||||
if (!isRunning() || !shouldAllowContactConnections()) return;
|
if (!isRunning() || !shouldAllowContactConnections()) return;
|
||||||
if (!connectionLimiter.canOpenContactConnection()) return;
|
if (!connectionLimiter.canOpenContactConnection()) return;
|
||||||
@@ -308,10 +305,9 @@ abstract class BluetoothPlugin<SS> implements DuplexPlugin, EventListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DuplexTransportConnection createConnection(ContactId c) {
|
public DuplexTransportConnection createConnection(TransportProperties p) {
|
||||||
if (!isRunning() || !shouldAllowContactConnections()) return null;
|
if (!isRunning() || !shouldAllowContactConnections()) return null;
|
||||||
if (!connectionLimiter.canOpenContactConnection()) return null;
|
if (!connectionLimiter.canOpenContactConnection()) return null;
|
||||||
TransportProperties p = callback.getRemoteProperties(c);
|
|
||||||
String address = p.get(PROP_ADDRESS);
|
String address = p.get(PROP_ADDRESS);
|
||||||
if (StringUtils.isNullOrEmpty(address)) return null;
|
if (StringUtils.isNullOrEmpty(address)) return null;
|
||||||
String uuid = p.get(PROP_UUID);
|
String uuid = p.get(PROP_UUID);
|
||||||
@@ -341,7 +337,7 @@ abstract class BluetoothPlugin<SS> implements DuplexPlugin, EventListener {
|
|||||||
try {
|
try {
|
||||||
ss = openServerSocket(uuid);
|
ss = openServerSocket(uuid);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
logException(LOG, WARNING, e);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if (!isRunning()) {
|
if (!isRunning()) {
|
||||||
|
|||||||
@@ -1,27 +1,22 @@
|
|||||||
package org.briarproject.bramble.plugin.file;
|
package org.briarproject.bramble.plugin.file;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.contact.ContactId;
|
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
import org.briarproject.bramble.api.plugin.TransportConnectionReader;
|
import org.briarproject.bramble.api.plugin.TransportConnectionReader;
|
||||||
import org.briarproject.bramble.api.plugin.TransportConnectionWriter;
|
import org.briarproject.bramble.api.plugin.TransportConnectionWriter;
|
||||||
import org.briarproject.bramble.api.plugin.simplex.SimplexPlugin;
|
import org.briarproject.bramble.api.plugin.simplex.SimplexPlugin;
|
||||||
import org.briarproject.bramble.api.plugin.simplex.SimplexPluginCallback;
|
import org.briarproject.bramble.api.plugin.simplex.SimplexPluginCallback;
|
||||||
|
import org.briarproject.bramble.api.properties.TransportProperties;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Locale;
|
|
||||||
import java.util.concurrent.Executor;
|
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
|
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
import static org.briarproject.bramble.api.transport.TransportConstants.MIN_STREAM_LENGTH;
|
import static org.briarproject.bramble.api.plugin.FileConstants.PROP_PATH;
|
||||||
|
import static org.briarproject.bramble.util.LogUtils.logException;
|
||||||
|
import static org.briarproject.bramble.util.StringUtils.isNullOrEmpty;
|
||||||
|
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
abstract class FilePlugin implements SimplexPlugin {
|
abstract class FilePlugin implements SimplexPlugin {
|
||||||
@@ -29,25 +24,15 @@ abstract class FilePlugin implements SimplexPlugin {
|
|||||||
private static final Logger LOG =
|
private static final Logger LOG =
|
||||||
Logger.getLogger(FilePlugin.class.getName());
|
Logger.getLogger(FilePlugin.class.getName());
|
||||||
|
|
||||||
protected final Executor ioExecutor;
|
|
||||||
protected final SimplexPluginCallback callback;
|
protected final SimplexPluginCallback callback;
|
||||||
protected final int maxLatency;
|
protected final int maxLatency;
|
||||||
protected final AtomicBoolean used = new AtomicBoolean(false);
|
|
||||||
|
|
||||||
protected volatile boolean running = false;
|
protected abstract void writerFinished(File f, boolean exception);
|
||||||
|
|
||||||
@Nullable
|
protected abstract void readerFinished(File f, boolean exception,
|
||||||
protected abstract File chooseOutputDirectory();
|
boolean recognised);
|
||||||
|
|
||||||
protected abstract Collection<File> findFilesByName(String filename);
|
FilePlugin(SimplexPluginCallback callback, int maxLatency) {
|
||||||
|
|
||||||
protected abstract void writerFinished(File f);
|
|
||||||
|
|
||||||
protected abstract void readerFinished(File f);
|
|
||||||
|
|
||||||
protected FilePlugin(Executor ioExecutor, SimplexPluginCallback callback,
|
|
||||||
int maxLatency) {
|
|
||||||
this.ioExecutor = ioExecutor;
|
|
||||||
this.callback = callback;
|
this.callback = callback;
|
||||||
this.maxLatency = maxLatency;
|
this.maxLatency = maxLatency;
|
||||||
}
|
}
|
||||||
@@ -58,81 +43,36 @@ abstract class FilePlugin implements SimplexPlugin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getMaxIdleTime() {
|
public TransportConnectionReader createReader(TransportProperties p) {
|
||||||
return Integer.MAX_VALUE; // We don't need keepalives
|
if (!isRunning()) return null;
|
||||||
}
|
String path = p.get(PROP_PATH);
|
||||||
|
if (isNullOrEmpty(path)) return null;
|
||||||
@Override
|
|
||||||
public boolean isRunning() {
|
|
||||||
return running;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public TransportConnectionReader createReader(ContactId c) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public TransportConnectionWriter createWriter(ContactId c) {
|
|
||||||
if (!running) return null;
|
|
||||||
return createWriter(createConnectionFilename());
|
|
||||||
}
|
|
||||||
|
|
||||||
private String createConnectionFilename() {
|
|
||||||
StringBuilder s = new StringBuilder(12);
|
|
||||||
for (int i = 0; i < 8; i++) s.append((char) ('a' + Math.random() * 26));
|
|
||||||
s.append(".dat");
|
|
||||||
return s.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Package access for testing
|
|
||||||
boolean isPossibleConnectionFilename(String filename) {
|
|
||||||
return filename.toLowerCase(Locale.US).matches("[a-z]{8}\\.dat");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private TransportConnectionWriter createWriter(String filename) {
|
|
||||||
if (!running) return null;
|
|
||||||
File dir = chooseOutputDirectory();
|
|
||||||
if (dir == null || !dir.exists() || !dir.isDirectory()) return null;
|
|
||||||
File f = new File(dir, filename);
|
|
||||||
try {
|
try {
|
||||||
long capacity = dir.getFreeSpace();
|
File file = new File(path);
|
||||||
if (capacity < MIN_STREAM_LENGTH) return null;
|
FileInputStream in = new FileInputStream(file);
|
||||||
OutputStream out = new FileOutputStream(f);
|
return new FileTransportReader(file, in, this);
|
||||||
return new FileTransportWriter(f, out, capacity, this);
|
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
logException(LOG, WARNING, e);
|
||||||
f.delete();
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void createReaderFromFile(File f) {
|
@Override
|
||||||
if (!running) return;
|
public TransportConnectionWriter createWriter(TransportProperties p) {
|
||||||
ioExecutor.execute(new ReaderCreator(f));
|
if (!isRunning()) return null;
|
||||||
}
|
String path = p.get(PROP_PATH);
|
||||||
|
if (isNullOrEmpty(path)) return null;
|
||||||
private class ReaderCreator implements Runnable {
|
try {
|
||||||
|
File file = new File(path);
|
||||||
private final File file;
|
if (!file.exists() && !file.createNewFile()) {
|
||||||
|
LOG.info("Failed to create file");
|
||||||
private ReaderCreator(File file) {
|
return null;
|
||||||
this.file = file;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
if (isPossibleConnectionFilename(file.getName())) {
|
|
||||||
try {
|
|
||||||
FileInputStream in = new FileInputStream(file);
|
|
||||||
callback.readerCreated(new FileTransportReader(file, in,
|
|
||||||
FilePlugin.this));
|
|
||||||
} catch (IOException e) {
|
|
||||||
if (LOG.isLoggable(WARNING))
|
|
||||||
LOG.log(WARNING, e.toString(), e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
FileOutputStream out = new FileOutputStream(file);
|
||||||
|
return new FileTransportWriter(file, out, this);
|
||||||
|
} catch (IOException e) {
|
||||||
|
logException(LOG, WARNING, e);
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import java.io.InputStream;
|
|||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
|
import static org.briarproject.bramble.util.LogUtils.logException;
|
||||||
|
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
class FileTransportReader implements TransportConnectionReader {
|
class FileTransportReader implements TransportConnectionReader {
|
||||||
@@ -36,11 +37,8 @@ class FileTransportReader implements TransportConnectionReader {
|
|||||||
try {
|
try {
|
||||||
in.close();
|
in.close();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
logException(LOG, WARNING, e);
|
||||||
}
|
|
||||||
if (recognised) {
|
|
||||||
file.delete();
|
|
||||||
plugin.readerFinished(file);
|
|
||||||
}
|
}
|
||||||
|
plugin.readerFinished(file, exception, recognised);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import java.io.OutputStream;
|
|||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
|
import static org.briarproject.bramble.util.LogUtils.logException;
|
||||||
|
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
class FileTransportWriter implements TransportConnectionWriter {
|
class FileTransportWriter implements TransportConnectionWriter {
|
||||||
@@ -18,14 +19,11 @@ class FileTransportWriter implements TransportConnectionWriter {
|
|||||||
|
|
||||||
private final File file;
|
private final File file;
|
||||||
private final OutputStream out;
|
private final OutputStream out;
|
||||||
private final long capacity;
|
|
||||||
private final FilePlugin plugin;
|
private final FilePlugin plugin;
|
||||||
|
|
||||||
FileTransportWriter(File file, OutputStream out, long capacity,
|
FileTransportWriter(File file, OutputStream out, FilePlugin plugin) {
|
||||||
FilePlugin plugin) {
|
|
||||||
this.file = file;
|
this.file = file;
|
||||||
this.out = out;
|
this.out = out;
|
||||||
this.capacity = capacity;
|
|
||||||
this.plugin = plugin;
|
this.plugin = plugin;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -39,11 +37,6 @@ class FileTransportWriter implements TransportConnectionWriter {
|
|||||||
return plugin.getMaxIdleTime();
|
return plugin.getMaxIdleTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public long getCapacity() {
|
|
||||||
return capacity;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public OutputStream getOutputStream() {
|
public OutputStream getOutputStream() {
|
||||||
return out;
|
return out;
|
||||||
@@ -54,9 +47,8 @@ class FileTransportWriter implements TransportConnectionWriter {
|
|||||||
try {
|
try {
|
||||||
out.close();
|
out.close();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
logException(LOG, WARNING, e);
|
||||||
}
|
}
|
||||||
if (exception) file.delete();
|
plugin.writerFinished(file, exception);
|
||||||
else plugin.writerFinished(file);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ import static org.briarproject.bramble.api.plugin.LanTcpConstants.ID;
|
|||||||
import static org.briarproject.bramble.api.plugin.LanTcpConstants.PREF_LAN_IP_PORTS;
|
import static org.briarproject.bramble.api.plugin.LanTcpConstants.PREF_LAN_IP_PORTS;
|
||||||
import static org.briarproject.bramble.api.plugin.LanTcpConstants.PROP_IP_PORTS;
|
import static org.briarproject.bramble.api.plugin.LanTcpConstants.PROP_IP_PORTS;
|
||||||
import static org.briarproject.bramble.util.ByteUtils.MAX_16_BIT_UNSIGNED;
|
import static org.briarproject.bramble.util.ByteUtils.MAX_16_BIT_UNSIGNED;
|
||||||
|
import static org.briarproject.bramble.util.LogUtils.logException;
|
||||||
import static org.briarproject.bramble.util.PrivacyUtils.scrubSocketAddress;
|
import static org.briarproject.bramble.util.PrivacyUtils.scrubSocketAddress;
|
||||||
|
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
@@ -295,7 +296,7 @@ class LanTcpPlugin extends TcpPlugin {
|
|||||||
try {
|
try {
|
||||||
ss.close();
|
ss.close();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
logException(LOG, WARNING, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import javax.xml.parsers.ParserConfigurationException;
|
|||||||
|
|
||||||
import static java.util.logging.Level.INFO;
|
import static java.util.logging.Level.INFO;
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
|
import static org.briarproject.bramble.util.LogUtils.logException;
|
||||||
import static org.briarproject.bramble.util.PrivacyUtils.scrubInetAddress;
|
import static org.briarproject.bramble.util.PrivacyUtils.scrubInetAddress;
|
||||||
|
|
||||||
@ThreadSafe
|
@ThreadSafe
|
||||||
@@ -59,7 +60,7 @@ class PortMapperImpl implements PortMapper {
|
|||||||
if (externalString != null)
|
if (externalString != null)
|
||||||
external = InetAddress.getByName(externalString);
|
external = InetAddress.getByName(externalString);
|
||||||
} catch (IOException | SAXException e) {
|
} catch (IOException | SAXException e) {
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
logException(LOG, WARNING, e);
|
||||||
}
|
}
|
||||||
return new MappingResult(internal, external, port, succeeded);
|
return new MappingResult(internal, external, port, succeeded);
|
||||||
}
|
}
|
||||||
@@ -76,7 +77,7 @@ class PortMapperImpl implements PortMapper {
|
|||||||
try {
|
try {
|
||||||
d.discover();
|
d.discover();
|
||||||
} catch (IOException | SAXException | ParserConfigurationException e) {
|
} catch (IOException | SAXException | ParserConfigurationException e) {
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
logException(LOG, WARNING, e);
|
||||||
}
|
}
|
||||||
gateway = d.getValidGateway();
|
gateway = d.getValidGateway();
|
||||||
}
|
}
|
||||||
@@ -87,7 +88,7 @@ class PortMapperImpl implements PortMapper {
|
|||||||
if (LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
LOG.info("Deleted mapping for port " + port);
|
LOG.info("Deleted mapping for port " + port);
|
||||||
} catch (IOException | SAXException e) {
|
} catch (IOException | SAXException e) {
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
logException(LOG, WARNING, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ import javax.annotation.Nullable;
|
|||||||
|
|
||||||
import static java.util.logging.Level.INFO;
|
import static java.util.logging.Level.INFO;
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
|
import static org.briarproject.bramble.util.LogUtils.logException;
|
||||||
import static org.briarproject.bramble.util.PrivacyUtils.scrubSocketAddress;
|
import static org.briarproject.bramble.util.PrivacyUtils.scrubSocketAddress;
|
||||||
|
|
||||||
@MethodsNotNullByDefault
|
@MethodsNotNullByDefault
|
||||||
@@ -152,7 +153,7 @@ abstract class TcpPlugin implements DuplexPlugin {
|
|||||||
try {
|
try {
|
||||||
if (ss != null) ss.close();
|
if (ss != null) ss.close();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
logException(LOG, WARNING, e);
|
||||||
} finally {
|
} finally {
|
||||||
callback.transportDisabled();
|
callback.transportDisabled();
|
||||||
}
|
}
|
||||||
@@ -207,20 +208,16 @@ abstract class TcpPlugin implements DuplexPlugin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void poll(Collection<ContactId> connected) {
|
public void poll(Map<ContactId, TransportProperties> contacts) {
|
||||||
if (!isRunning()) return;
|
if (!isRunning()) return;
|
||||||
backoff.increment();
|
backoff.increment();
|
||||||
Map<ContactId, TransportProperties> remote =
|
for (Entry<ContactId, TransportProperties> e : contacts.entrySet()) {
|
||||||
callback.getRemoteProperties();
|
connectAndCallBack(e.getKey(), e.getValue());
|
||||||
for (Entry<ContactId, TransportProperties> e : remote.entrySet()) {
|
|
||||||
ContactId c = e.getKey();
|
|
||||||
if (!connected.contains(c)) connectAndCallBack(c, e.getValue());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void connectAndCallBack(ContactId c, TransportProperties p) {
|
private void connectAndCallBack(ContactId c, TransportProperties p) {
|
||||||
ioExecutor.execute(() -> {
|
ioExecutor.execute(() -> {
|
||||||
if (!isRunning()) return;
|
|
||||||
DuplexTransportConnection d = createConnection(p);
|
DuplexTransportConnection d = createConnection(p);
|
||||||
if (d != null) {
|
if (d != null) {
|
||||||
backoff.reset();
|
backoff.reset();
|
||||||
@@ -230,13 +227,8 @@ abstract class TcpPlugin implements DuplexPlugin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DuplexTransportConnection createConnection(ContactId c) {
|
public DuplexTransportConnection createConnection(TransportProperties p) {
|
||||||
if (!isRunning()) return null;
|
if (!isRunning()) return null;
|
||||||
return createConnection(callback.getRemoteProperties(c));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private DuplexTransportConnection createConnection(TransportProperties p) {
|
|
||||||
for (InetSocketAddress remote : getRemoteSocketAddresses(p)) {
|
for (InetSocketAddress remote : getRemoteSocketAddresses(p)) {
|
||||||
if (!isConnectable(remote)) {
|
if (!isConnectable(remote)) {
|
||||||
if (LOG.isLoggable(INFO)) {
|
if (LOG.isLoggable(INFO)) {
|
||||||
@@ -315,7 +307,7 @@ abstract class TcpPlugin implements DuplexPlugin {
|
|||||||
try {
|
try {
|
||||||
ifaces = Collections.list(NetworkInterface.getNetworkInterfaces());
|
ifaces = Collections.list(NetworkInterface.getNetworkInterfaces());
|
||||||
} catch (SocketException e) {
|
} catch (SocketException e) {
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
logException(LOG, WARNING, e);
|
||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
List<InetAddress> addrs = new ArrayList<>();
|
List<InetAddress> addrs = new ArrayList<>();
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import java.util.logging.Logger;
|
|||||||
|
|
||||||
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
|
import static org.briarproject.bramble.util.LogUtils.logException;
|
||||||
|
|
||||||
@MethodsNotNullByDefault
|
@MethodsNotNullByDefault
|
||||||
@ParametersNotNullByDefault
|
@ParametersNotNullByDefault
|
||||||
@@ -78,7 +79,7 @@ class ReliabilityLayerImpl implements ReliabilityLayer, WriteHandler {
|
|||||||
Thread.currentThread().interrupt();
|
Thread.currentThread().interrupt();
|
||||||
running = false;
|
running = false;
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
logException(LOG, WARNING, e);
|
||||||
running = false;
|
running = false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,7 +1,12 @@
|
|||||||
package org.briarproject.bramble.reporting;
|
package org.briarproject.bramble.reporting;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.crypto.CryptoComponent;
|
import org.briarproject.bramble.api.crypto.CryptoComponent;
|
||||||
|
import org.briarproject.bramble.api.event.Event;
|
||||||
|
import org.briarproject.bramble.api.event.EventListener;
|
||||||
|
import org.briarproject.bramble.api.lifecycle.IoExecutor;
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
import org.briarproject.bramble.api.plugin.TorConstants;
|
||||||
|
import org.briarproject.bramble.api.plugin.event.TransportEnabledEvent;
|
||||||
import org.briarproject.bramble.api.reporting.DevConfig;
|
import org.briarproject.bramble.api.reporting.DevConfig;
|
||||||
import org.briarproject.bramble.api.reporting.DevReporter;
|
import org.briarproject.bramble.api.reporting.DevReporter;
|
||||||
import org.briarproject.bramble.util.IoUtils;
|
import org.briarproject.bramble.util.IoUtils;
|
||||||
@@ -18,17 +23,20 @@ import java.io.OutputStream;
|
|||||||
import java.io.OutputStreamWriter;
|
import java.io.OutputStreamWriter;
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
|
import java.util.concurrent.Executor;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import javax.annotation.concurrent.Immutable;
|
import javax.annotation.concurrent.Immutable;
|
||||||
|
import javax.inject.Inject;
|
||||||
import javax.net.SocketFactory;
|
import javax.net.SocketFactory;
|
||||||
|
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
|
import static org.briarproject.bramble.util.LogUtils.logException;
|
||||||
|
|
||||||
@Immutable
|
@Immutable
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
class DevReporterImpl implements DevReporter {
|
class DevReporterImpl implements DevReporter, EventListener {
|
||||||
|
|
||||||
private static final Logger LOG =
|
private static final Logger LOG =
|
||||||
Logger.getLogger(DevReporterImpl.class.getName());
|
Logger.getLogger(DevReporterImpl.class.getName());
|
||||||
@@ -36,12 +44,15 @@ class DevReporterImpl implements DevReporter {
|
|||||||
private static final int SOCKET_TIMEOUT = 30 * 1000; // 30 seconds
|
private static final int SOCKET_TIMEOUT = 30 * 1000; // 30 seconds
|
||||||
private static final int LINE_LENGTH = 70;
|
private static final int LINE_LENGTH = 70;
|
||||||
|
|
||||||
|
private final Executor ioExecutor;
|
||||||
private final CryptoComponent crypto;
|
private final CryptoComponent crypto;
|
||||||
private final DevConfig devConfig;
|
private final DevConfig devConfig;
|
||||||
private final SocketFactory torSocketFactory;
|
private final SocketFactory torSocketFactory;
|
||||||
|
|
||||||
DevReporterImpl(CryptoComponent crypto, DevConfig devConfig,
|
@Inject
|
||||||
SocketFactory torSocketFactory) {
|
DevReporterImpl(@IoExecutor Executor ioExecutor, CryptoComponent crypto,
|
||||||
|
DevConfig devConfig, SocketFactory torSocketFactory) {
|
||||||
|
this.ioExecutor = ioExecutor;
|
||||||
this.crypto = crypto;
|
this.crypto = crypto;
|
||||||
this.devConfig = devConfig;
|
this.devConfig = devConfig;
|
||||||
this.torSocketFactory = torSocketFactory;
|
this.torSocketFactory = torSocketFactory;
|
||||||
@@ -63,6 +74,7 @@ class DevReporterImpl implements DevReporter {
|
|||||||
@Override
|
@Override
|
||||||
public void encryptReportToFile(File reportDir, String filename,
|
public void encryptReportToFile(File reportDir, String filename,
|
||||||
String report) throws FileNotFoundException {
|
String report) throws FileNotFoundException {
|
||||||
|
LOG.info("Encrypting report to file");
|
||||||
byte[] plaintext = StringUtils.toUtf8(report);
|
byte[] plaintext = StringUtils.toUtf8(report);
|
||||||
byte[] ciphertext = crypto.encryptToKey(devConfig.getDevPublicKey(),
|
byte[] ciphertext = crypto.encryptToKey(devConfig.getDevPublicKey(),
|
||||||
plaintext);
|
plaintext);
|
||||||
@@ -82,7 +94,17 @@ class DevReporterImpl implements DevReporter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void sendReports(File reportDir) {
|
public void eventOccurred(Event e) {
|
||||||
|
if (e instanceof TransportEnabledEvent) {
|
||||||
|
TransportEnabledEvent t = (TransportEnabledEvent) e;
|
||||||
|
if (t.getTransportId().equals(TorConstants.ID))
|
||||||
|
ioExecutor.execute(this::sendReports);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sendReports() {
|
||||||
|
File reportDir = devConfig.getReportDir();
|
||||||
File[] reports = reportDir.listFiles();
|
File[] reports = reportDir.listFiles();
|
||||||
if (reports == null || reports.length == 0)
|
if (reports == null || reports.length == 0)
|
||||||
return; // No reports to send
|
return; // No reports to send
|
||||||
@@ -111,7 +133,7 @@ class DevReporterImpl implements DevReporter {
|
|||||||
try {
|
try {
|
||||||
if (c != null) c.close();
|
if (c != null) c.close();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
logException(LOG, WARNING, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -119,7 +141,7 @@ class DevReporterImpl implements DevReporter {
|
|||||||
try {
|
try {
|
||||||
if (s != null) s.close();
|
if (s != null) s.close();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
logException(LOG, WARNING, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
package org.briarproject.bramble.reporting;
|
package org.briarproject.bramble.reporting;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.crypto.CryptoComponent;
|
import org.briarproject.bramble.api.event.EventBus;
|
||||||
import org.briarproject.bramble.api.reporting.DevConfig;
|
|
||||||
import org.briarproject.bramble.api.reporting.DevReporter;
|
import org.briarproject.bramble.api.reporting.DevReporter;
|
||||||
|
|
||||||
import javax.net.SocketFactory;
|
import javax.inject.Inject;
|
||||||
|
import javax.inject.Singleton;
|
||||||
|
|
||||||
import dagger.Module;
|
import dagger.Module;
|
||||||
import dagger.Provides;
|
import dagger.Provides;
|
||||||
@@ -12,9 +12,16 @@ import dagger.Provides;
|
|||||||
@Module
|
@Module
|
||||||
public class ReportingModule {
|
public class ReportingModule {
|
||||||
|
|
||||||
|
public static class EagerSingletons {
|
||||||
|
@Inject
|
||||||
|
DevReporter devReporter;
|
||||||
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
DevReporter provideDevReporter(CryptoComponent crypto,
|
@Singleton
|
||||||
DevConfig devConfig, SocketFactory torSocketFactory) {
|
DevReporter provideDevReporter(DevReporterImpl devReporter,
|
||||||
return new DevReporterImpl(crypto, devConfig, torSocketFactory);
|
EventBus eventBus) {
|
||||||
|
eventBus.addListener(devReporter);
|
||||||
|
return devReporter;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ import static java.util.logging.Level.WARNING;
|
|||||||
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.LifecycleState.STOPPING;
|
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.LifecycleState.STOPPING;
|
||||||
import static org.briarproject.bramble.api.record.Record.MAX_RECORD_PAYLOAD_BYTES;
|
import static org.briarproject.bramble.api.record.Record.MAX_RECORD_PAYLOAD_BYTES;
|
||||||
import static org.briarproject.bramble.api.sync.SyncConstants.MAX_MESSAGE_IDS;
|
import static org.briarproject.bramble.api.sync.SyncConstants.MAX_MESSAGE_IDS;
|
||||||
|
import static org.briarproject.bramble.util.LogUtils.logException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An outgoing {@link SyncSession} suitable for duplex transports. The session
|
* An outgoing {@link SyncSession} suitable for duplex transports. The session
|
||||||
@@ -240,7 +241,7 @@ class DuplexOutgoingSession implements SyncSession, EventListener {
|
|||||||
LOG.info("Generated ack: " + (a != null));
|
LOG.info("Generated ack: " + (a != null));
|
||||||
if (a != null) writerTasks.add(new WriteAck(a));
|
if (a != null) writerTasks.add(new WriteAck(a));
|
||||||
} catch (DbException e) {
|
} catch (DbException e) {
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
logException(LOG, WARNING, e);
|
||||||
interrupt();
|
interrupt();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -287,7 +288,7 @@ class DuplexOutgoingSession implements SyncSession, EventListener {
|
|||||||
LOG.info("Generated batch: " + (b != null));
|
LOG.info("Generated batch: " + (b != null));
|
||||||
if (b != null) writerTasks.add(new WriteBatch(b));
|
if (b != null) writerTasks.add(new WriteBatch(b));
|
||||||
} catch (DbException e) {
|
} catch (DbException e) {
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
logException(LOG, WARNING, e);
|
||||||
interrupt();
|
interrupt();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -334,7 +335,7 @@ class DuplexOutgoingSession implements SyncSession, EventListener {
|
|||||||
LOG.info("Generated offer: " + (o != null));
|
LOG.info("Generated offer: " + (o != null));
|
||||||
if (o != null) writerTasks.add(new WriteOffer(o));
|
if (o != null) writerTasks.add(new WriteOffer(o));
|
||||||
} catch (DbException e) {
|
} catch (DbException e) {
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
logException(LOG, WARNING, e);
|
||||||
interrupt();
|
interrupt();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -379,7 +380,7 @@ class DuplexOutgoingSession implements SyncSession, EventListener {
|
|||||||
LOG.info("Generated request: " + (r != null));
|
LOG.info("Generated request: " + (r != null));
|
||||||
if (r != null) writerTasks.add(new WriteRequest(r));
|
if (r != null) writerTasks.add(new WriteRequest(r));
|
||||||
} catch (DbException e) {
|
} catch (DbException e) {
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
logException(LOG, WARNING, e);
|
||||||
interrupt();
|
interrupt();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ import javax.annotation.concurrent.ThreadSafe;
|
|||||||
|
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.LifecycleState.STOPPING;
|
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.LifecycleState.STOPPING;
|
||||||
|
import static org.briarproject.bramble.util.LogUtils.logException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An incoming {@link SyncSession}.
|
* An incoming {@link SyncSession}.
|
||||||
@@ -127,7 +128,7 @@ class IncomingSession implements SyncSession, EventListener {
|
|||||||
db.endTransaction(txn);
|
db.endTransaction(txn);
|
||||||
}
|
}
|
||||||
} catch (DbException e) {
|
} catch (DbException e) {
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
logException(LOG, WARNING, e);
|
||||||
interrupt();
|
interrupt();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -153,7 +154,7 @@ class IncomingSession implements SyncSession, EventListener {
|
|||||||
db.endTransaction(txn);
|
db.endTransaction(txn);
|
||||||
}
|
}
|
||||||
} catch (DbException e) {
|
} catch (DbException e) {
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
logException(LOG, WARNING, e);
|
||||||
interrupt();
|
interrupt();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -179,7 +180,7 @@ class IncomingSession implements SyncSession, EventListener {
|
|||||||
db.endTransaction(txn);
|
db.endTransaction(txn);
|
||||||
}
|
}
|
||||||
} catch (DbException e) {
|
} catch (DbException e) {
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
logException(LOG, WARNING, e);
|
||||||
interrupt();
|
interrupt();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -205,7 +206,7 @@ class IncomingSession implements SyncSession, EventListener {
|
|||||||
db.endTransaction(txn);
|
db.endTransaction(txn);
|
||||||
}
|
}
|
||||||
} catch (DbException e) {
|
} catch (DbException e) {
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
logException(LOG, WARNING, e);
|
||||||
interrupt();
|
interrupt();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ import static java.util.logging.Level.WARNING;
|
|||||||
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.LifecycleState.STOPPING;
|
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.LifecycleState.STOPPING;
|
||||||
import static org.briarproject.bramble.api.record.Record.MAX_RECORD_PAYLOAD_BYTES;
|
import static org.briarproject.bramble.api.record.Record.MAX_RECORD_PAYLOAD_BYTES;
|
||||||
import static org.briarproject.bramble.api.sync.SyncConstants.MAX_MESSAGE_IDS;
|
import static org.briarproject.bramble.api.sync.SyncConstants.MAX_MESSAGE_IDS;
|
||||||
|
import static org.briarproject.bramble.util.LogUtils.logException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An outgoing {@link SyncSession} suitable for simplex transports. The session
|
* An outgoing {@link SyncSession} suitable for simplex transports. The session
|
||||||
@@ -139,7 +140,7 @@ class SimplexOutgoingSession implements SyncSession, EventListener {
|
|||||||
if (a == null) decrementOutstandingQueries();
|
if (a == null) decrementOutstandingQueries();
|
||||||
else writerTasks.add(new WriteAck(a));
|
else writerTasks.add(new WriteAck(a));
|
||||||
} catch (DbException e) {
|
} catch (DbException e) {
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
logException(LOG, WARNING, e);
|
||||||
interrupt();
|
interrupt();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -184,7 +185,7 @@ class SimplexOutgoingSession implements SyncSession, EventListener {
|
|||||||
if (b == null) decrementOutstandingQueries();
|
if (b == null) decrementOutstandingQueries();
|
||||||
else writerTasks.add(new WriteBatch(b));
|
else writerTasks.add(new WriteBatch(b));
|
||||||
} catch (DbException e) {
|
} catch (DbException e) {
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
logException(LOG, WARNING, e);
|
||||||
interrupt();
|
interrupt();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ import static java.util.logging.Level.WARNING;
|
|||||||
import static org.briarproject.bramble.api.sync.ValidationManager.State.DELIVERED;
|
import static org.briarproject.bramble.api.sync.ValidationManager.State.DELIVERED;
|
||||||
import static org.briarproject.bramble.api.sync.ValidationManager.State.INVALID;
|
import static org.briarproject.bramble.api.sync.ValidationManager.State.INVALID;
|
||||||
import static org.briarproject.bramble.api.sync.ValidationManager.State.PENDING;
|
import static org.briarproject.bramble.api.sync.ValidationManager.State.PENDING;
|
||||||
|
import static org.briarproject.bramble.util.LogUtils.logException;
|
||||||
|
|
||||||
@ThreadSafe
|
@ThreadSafe
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
@@ -110,7 +111,7 @@ class ValidationManagerImpl implements ValidationManager, Service,
|
|||||||
}
|
}
|
||||||
validateNextMessageAsync(unvalidated);
|
validateNextMessageAsync(unvalidated);
|
||||||
} catch (DbException e) {
|
} catch (DbException e) {
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
logException(LOG, WARNING, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -144,7 +145,7 @@ class ValidationManagerImpl implements ValidationManager, Service,
|
|||||||
LOG.info("Group removed before validation");
|
LOG.info("Group removed before validation");
|
||||||
validateNextMessageAsync(unvalidated);
|
validateNextMessageAsync(unvalidated);
|
||||||
} catch (DbException e) {
|
} catch (DbException e) {
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
logException(LOG, WARNING, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -165,7 +166,7 @@ class ValidationManagerImpl implements ValidationManager, Service,
|
|||||||
}
|
}
|
||||||
deliverNextPendingMessageAsync(pending);
|
deliverNextPendingMessageAsync(pending);
|
||||||
} catch (DbException e) {
|
} catch (DbException e) {
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
logException(LOG, WARNING, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -231,7 +232,7 @@ class ValidationManagerImpl implements ValidationManager, Service,
|
|||||||
LOG.info("Group removed before delivery");
|
LOG.info("Group removed before delivery");
|
||||||
deliverNextPendingMessageAsync(pending);
|
deliverNextPendingMessageAsync(pending);
|
||||||
} catch (DbException e) {
|
} catch (DbException e) {
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
logException(LOG, WARNING, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -252,8 +253,7 @@ class ValidationManagerImpl implements ValidationManager, Service,
|
|||||||
storeMessageContextAsync(m, g.getClientId(),
|
storeMessageContextAsync(m, g.getClientId(),
|
||||||
g.getMajorVersion(), context);
|
g.getMajorVersion(), context);
|
||||||
} catch (InvalidMessageException e) {
|
} catch (InvalidMessageException e) {
|
||||||
if (LOG.isLoggable(INFO))
|
logException(LOG, INFO, e);
|
||||||
LOG.log(INFO, e.toString(), e);
|
|
||||||
Queue<MessageId> invalidate = new LinkedList<>();
|
Queue<MessageId> invalidate = new LinkedList<>();
|
||||||
invalidate.add(m.getId());
|
invalidate.add(m.getId());
|
||||||
invalidateNextMessageAsync(invalidate);
|
invalidateNextMessageAsync(invalidate);
|
||||||
@@ -326,7 +326,7 @@ class ValidationManagerImpl implements ValidationManager, Service,
|
|||||||
} catch (NoSuchGroupException e) {
|
} catch (NoSuchGroupException e) {
|
||||||
LOG.info("Group removed during validation");
|
LOG.info("Group removed during validation");
|
||||||
} catch (DbException e) {
|
} catch (DbException e) {
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
logException(LOG, WARNING, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -377,7 +377,7 @@ class ValidationManagerImpl implements ValidationManager, Service,
|
|||||||
}
|
}
|
||||||
shareNextMessageAsync(toShare);
|
shareNextMessageAsync(toShare);
|
||||||
} catch (DbException e) {
|
} catch (DbException e) {
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
logException(LOG, WARNING, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -412,7 +412,7 @@ class ValidationManagerImpl implements ValidationManager, Service,
|
|||||||
LOG.info("Group removed before sharing");
|
LOG.info("Group removed before sharing");
|
||||||
shareNextMessageAsync(toShare);
|
shareNextMessageAsync(toShare);
|
||||||
} catch (DbException e) {
|
} catch (DbException e) {
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
logException(LOG, WARNING, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -440,7 +440,7 @@ class ValidationManagerImpl implements ValidationManager, Service,
|
|||||||
LOG.info("Message removed before invalidation");
|
LOG.info("Message removed before invalidation");
|
||||||
invalidateNextMessageAsync(invalidate);
|
invalidateNextMessageAsync(invalidate);
|
||||||
} catch (DbException e) {
|
} catch (DbException e) {
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
logException(LOG, WARNING, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -492,7 +492,7 @@ class ValidationManagerImpl implements ValidationManager, Service,
|
|||||||
} catch (NoSuchGroupException e) {
|
} catch (NoSuchGroupException e) {
|
||||||
LOG.info("Group removed before validation");
|
LOG.info("Group removed before validation");
|
||||||
} catch (DbException e) {
|
} catch (DbException e) {
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
logException(LOG, WARNING, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import java.util.logging.Logger;
|
|||||||
import javax.annotation.concurrent.Immutable;
|
import javax.annotation.concurrent.Immutable;
|
||||||
|
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
|
import static org.briarproject.bramble.util.LogUtils.logException;
|
||||||
|
|
||||||
@Immutable
|
@Immutable
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
@@ -49,7 +50,7 @@ class LinuxSecureRandomProvider extends AbstractSecureRandomProvider {
|
|||||||
out.close();
|
out.close();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
// On some devices /dev/urandom isn't writable - this isn't fatal
|
// On some devices /dev/urandom isn't writable - this isn't fatal
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
logException(LOG, WARNING, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import java.security.SecureRandomSpi;
|
|||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
|
import static org.briarproject.bramble.util.LogUtils.logException;
|
||||||
|
|
||||||
public class LinuxSecureRandomSpi extends SecureRandomSpi {
|
public class LinuxSecureRandomSpi extends SecureRandomSpi {
|
||||||
|
|
||||||
@@ -39,7 +40,7 @@ public class LinuxSecureRandomSpi extends SecureRandomSpi {
|
|||||||
out.close();
|
out.close();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
// On some devices /dev/urandom isn't writable - this isn't fatal
|
// On some devices /dev/urandom isn't writable - this isn't fatal
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
logException(LOG, WARNING, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -99,39 +99,18 @@ class KeyManagerImpl implements KeyManager, Service, EventListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addContact(Transaction txn, ContactId c, SecretKey master,
|
public Map<TransportId, KeySetId> addContact(Transaction txn, ContactId c,
|
||||||
long timestamp, boolean alice) throws DbException {
|
SecretKey master, long timestamp, boolean alice, boolean active)
|
||||||
for (TransportKeyManager m : managers.values())
|
|
||||||
m.addContact(txn, c, master, timestamp, alice);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Map<TransportId, KeySetId> addUnboundKeys(Transaction txn,
|
|
||||||
SecretKey master, long timestamp, boolean alice)
|
|
||||||
throws DbException {
|
throws DbException {
|
||||||
Map<TransportId, KeySetId> ids = new HashMap<>();
|
Map<TransportId, KeySetId> ids = new HashMap<>();
|
||||||
for (Entry<TransportId, TransportKeyManager> e : managers.entrySet()) {
|
for (Entry<TransportId, TransportKeyManager> e : managers.entrySet()) {
|
||||||
TransportId t = e.getKey();
|
TransportId t = e.getKey();
|
||||||
TransportKeyManager m = e.getValue();
|
TransportKeyManager m = e.getValue();
|
||||||
ids.put(t, m.addUnboundKeys(txn, master, timestamp, alice));
|
ids.put(t, m.addContact(txn, c, master, timestamp, alice, active));
|
||||||
}
|
}
|
||||||
return ids;
|
return ids;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void bindKeys(Transaction txn, ContactId c,
|
|
||||||
Map<TransportId, KeySetId> keys) throws DbException {
|
|
||||||
for (Entry<TransportId, KeySetId> e : keys.entrySet()) {
|
|
||||||
TransportId t = e.getKey();
|
|
||||||
TransportKeyManager m = managers.get(t);
|
|
||||||
if (m == null) {
|
|
||||||
if (LOG.isLoggable(INFO)) LOG.info("No key manager for " + t);
|
|
||||||
} else {
|
|
||||||
m.bindKeys(txn, c, e.getValue());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void activateKeys(Transaction txn, Map<TransportId, KeySetId> keys)
|
public void activateKeys(Transaction txn, Map<TransportId, KeySetId> keys)
|
||||||
throws DbException {
|
throws DbException {
|
||||||
@@ -146,24 +125,10 @@ class KeyManagerImpl implements KeyManager, Service, EventListener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void removeKeys(Transaction txn, Map<TransportId, KeySetId> keys)
|
|
||||||
throws DbException {
|
|
||||||
for (Entry<TransportId, KeySetId> e : keys.entrySet()) {
|
|
||||||
TransportId t = e.getKey();
|
|
||||||
TransportKeyManager m = managers.get(t);
|
|
||||||
if (m == null) {
|
|
||||||
if (LOG.isLoggable(INFO)) LOG.info("No key manager for " + t);
|
|
||||||
} else {
|
|
||||||
m.removeKeys(txn, e.getValue());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean canSendOutgoingStreams(ContactId c, TransportId t) {
|
public boolean canSendOutgoingStreams(ContactId c, TransportId t) {
|
||||||
TransportKeyManager m = managers.get(t);
|
TransportKeyManager m = managers.get(t);
|
||||||
return m == null ? false : m.canSendOutgoingStreams(c);
|
return m != null && m.canSendOutgoingStreams(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -3,32 +3,28 @@ package org.briarproject.bramble.transport;
|
|||||||
import org.briarproject.bramble.api.contact.ContactId;
|
import org.briarproject.bramble.api.contact.ContactId;
|
||||||
import org.briarproject.bramble.api.transport.KeySetId;
|
import org.briarproject.bramble.api.transport.KeySetId;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
class MutableKeySet {
|
||||||
|
|
||||||
public class MutableKeySet {
|
|
||||||
|
|
||||||
private final KeySetId keySetId;
|
private final KeySetId keySetId;
|
||||||
@Nullable
|
|
||||||
private final ContactId contactId;
|
private final ContactId contactId;
|
||||||
private final MutableTransportKeys transportKeys;
|
private final MutableTransportKeys transportKeys;
|
||||||
|
|
||||||
public MutableKeySet(KeySetId keySetId, @Nullable ContactId contactId,
|
MutableKeySet(KeySetId keySetId, ContactId contactId,
|
||||||
MutableTransportKeys transportKeys) {
|
MutableTransportKeys transportKeys) {
|
||||||
this.keySetId = keySetId;
|
this.keySetId = keySetId;
|
||||||
this.contactId = contactId;
|
this.contactId = contactId;
|
||||||
this.transportKeys = transportKeys;
|
this.transportKeys = transportKeys;
|
||||||
}
|
}
|
||||||
|
|
||||||
public KeySetId getKeySetId() {
|
KeySetId getKeySetId() {
|
||||||
return keySetId;
|
return keySetId;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
ContactId getContactId() {
|
||||||
public ContactId getContactId() {
|
|
||||||
return contactId;
|
return contactId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public MutableTransportKeys getTransportKeys() {
|
MutableTransportKeys getTransportKeys() {
|
||||||
return transportKeys;
|
return transportKeys;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,18 +15,11 @@ interface TransportKeyManager {
|
|||||||
|
|
||||||
void start(Transaction txn) throws DbException;
|
void start(Transaction txn) throws DbException;
|
||||||
|
|
||||||
void addContact(Transaction txn, ContactId c, SecretKey master,
|
KeySetId addContact(Transaction txn, ContactId c, SecretKey master,
|
||||||
long timestamp, boolean alice) throws DbException;
|
long timestamp, boolean alice, boolean active) throws DbException;
|
||||||
|
|
||||||
KeySetId addUnboundKeys(Transaction txn, SecretKey master, long timestamp,
|
|
||||||
boolean alice) throws DbException;
|
|
||||||
|
|
||||||
void bindKeys(Transaction txn, ContactId c, KeySetId k) throws DbException;
|
|
||||||
|
|
||||||
void activateKeys(Transaction txn, KeySetId k) throws DbException;
|
void activateKeys(Transaction txn, KeySetId k) throws DbException;
|
||||||
|
|
||||||
void removeKeys(Transaction txn, KeySetId k) throws DbException;
|
|
||||||
|
|
||||||
void removeContact(ContactId c);
|
void removeContact(ContactId c);
|
||||||
|
|
||||||
boolean canSendOutgoingStreams(ContactId c);
|
boolean canSendOutgoingStreams(ContactId c);
|
||||||
|
|||||||
@@ -28,7 +28,6 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
|||||||
import java.util.concurrent.locks.ReentrantLock;
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
import javax.annotation.concurrent.ThreadSafe;
|
import javax.annotation.concurrent.ThreadSafe;
|
||||||
|
|
||||||
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
||||||
@@ -37,6 +36,7 @@ import static org.briarproject.bramble.api.transport.TransportConstants.MAX_CLOC
|
|||||||
import static org.briarproject.bramble.api.transport.TransportConstants.PROTOCOL_VERSION;
|
import static org.briarproject.bramble.api.transport.TransportConstants.PROTOCOL_VERSION;
|
||||||
import static org.briarproject.bramble.api.transport.TransportConstants.TAG_LENGTH;
|
import static org.briarproject.bramble.api.transport.TransportConstants.TAG_LENGTH;
|
||||||
import static org.briarproject.bramble.util.ByteUtils.MAX_32_BIT_UNSIGNED;
|
import static org.briarproject.bramble.util.ByteUtils.MAX_32_BIT_UNSIGNED;
|
||||||
|
import static org.briarproject.bramble.util.LogUtils.logException;
|
||||||
|
|
||||||
@ThreadSafe
|
@ThreadSafe
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
@@ -119,16 +119,14 @@ class TransportKeyManagerImpl implements TransportKeyManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Locking: lock
|
// Locking: lock
|
||||||
private void addKeys(KeySetId keySetId, @Nullable ContactId contactId,
|
private void addKeys(KeySetId keySetId, ContactId contactId,
|
||||||
MutableTransportKeys m) {
|
MutableTransportKeys m) {
|
||||||
MutableKeySet ks = new MutableKeySet(keySetId, contactId, m);
|
MutableKeySet ks = new MutableKeySet(keySetId, contactId, m);
|
||||||
keys.put(keySetId, ks);
|
keys.put(keySetId, ks);
|
||||||
if (contactId != null) {
|
encodeTags(keySetId, contactId, m.getPreviousIncomingKeys());
|
||||||
encodeTags(keySetId, contactId, m.getPreviousIncomingKeys());
|
encodeTags(keySetId, contactId, m.getCurrentIncomingKeys());
|
||||||
encodeTags(keySetId, contactId, m.getCurrentIncomingKeys());
|
encodeTags(keySetId, contactId, m.getNextIncomingKeys());
|
||||||
encodeTags(keySetId, contactId, m.getNextIncomingKeys());
|
considerReplacingOutgoingKeys(ks);
|
||||||
considerReplacingOutgoingKeys(ks);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Locking: lock
|
// Locking: lock
|
||||||
@@ -150,8 +148,9 @@ class TransportKeyManagerImpl implements TransportKeyManager {
|
|||||||
if (ks.getTransportKeys().getCurrentOutgoingKeys().isActive()) {
|
if (ks.getTransportKeys().getCurrentOutgoingKeys().isActive()) {
|
||||||
MutableKeySet old = outContexts.get(ks.getContactId());
|
MutableKeySet old = outContexts.get(ks.getContactId());
|
||||||
if (old == null ||
|
if (old == null ||
|
||||||
old.getKeySetId().getInt() < ks.getKeySetId().getInt())
|
old.getKeySetId().getInt() < ks.getKeySetId().getInt()) {
|
||||||
outContexts.put(ks.getContactId(), ks);
|
outContexts.put(ks.getContactId(), ks);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -171,26 +170,14 @@ class TransportKeyManagerImpl implements TransportKeyManager {
|
|||||||
db.endTransaction(txn);
|
db.endTransaction(txn);
|
||||||
}
|
}
|
||||||
} catch (DbException e) {
|
} catch (DbException e) {
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
logException(LOG, WARNING, e);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addContact(Transaction txn, ContactId c, SecretKey master,
|
public KeySetId addContact(Transaction txn, ContactId c, SecretKey master,
|
||||||
long timestamp, boolean alice) throws DbException {
|
long timestamp, boolean alice, boolean active) throws DbException {
|
||||||
deriveAndAddKeys(txn, c, master, timestamp, alice, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public KeySetId addUnboundKeys(Transaction txn, SecretKey master,
|
|
||||||
long timestamp, boolean alice) throws DbException {
|
|
||||||
return deriveAndAddKeys(txn, null, master, timestamp, alice, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
private KeySetId deriveAndAddKeys(Transaction txn, @Nullable ContactId c,
|
|
||||||
SecretKey master, long timestamp, boolean alice, boolean active)
|
|
||||||
throws DbException {
|
|
||||||
lock.lock();
|
lock.lock();
|
||||||
try {
|
try {
|
||||||
// Work out what rotation period the timestamp belongs to
|
// Work out what rotation period the timestamp belongs to
|
||||||
@@ -211,31 +198,12 @@ class TransportKeyManagerImpl implements TransportKeyManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void bindKeys(Transaction txn, ContactId c, KeySetId k)
|
|
||||||
throws DbException {
|
|
||||||
lock.lock();
|
|
||||||
try {
|
|
||||||
MutableKeySet ks = keys.get(k);
|
|
||||||
if (ks == null) throw new IllegalArgumentException();
|
|
||||||
// Check that the keys haven't already been bound
|
|
||||||
if (ks.getContactId() != null) throw new IllegalArgumentException();
|
|
||||||
MutableTransportKeys m = ks.getTransportKeys();
|
|
||||||
addKeys(k, c, m);
|
|
||||||
db.bindTransportKeys(txn, c, m.getTransportId(), k);
|
|
||||||
} finally {
|
|
||||||
lock.unlock();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void activateKeys(Transaction txn, KeySetId k) throws DbException {
|
public void activateKeys(Transaction txn, KeySetId k) throws DbException {
|
||||||
lock.lock();
|
lock.lock();
|
||||||
try {
|
try {
|
||||||
MutableKeySet ks = keys.get(k);
|
MutableKeySet ks = keys.get(k);
|
||||||
if (ks == null) throw new IllegalArgumentException();
|
if (ks == null) throw new IllegalArgumentException();
|
||||||
// Check that the keys have been bound
|
|
||||||
if (ks.getContactId() == null) throw new IllegalArgumentException();
|
|
||||||
MutableTransportKeys m = ks.getTransportKeys();
|
MutableTransportKeys m = ks.getTransportKeys();
|
||||||
m.getCurrentOutgoingKeys().activate();
|
m.getCurrentOutgoingKeys().activate();
|
||||||
considerReplacingOutgoingKeys(ks);
|
considerReplacingOutgoingKeys(ks);
|
||||||
@@ -245,21 +213,6 @@ class TransportKeyManagerImpl implements TransportKeyManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void removeKeys(Transaction txn, KeySetId k) throws DbException {
|
|
||||||
lock.lock();
|
|
||||||
try {
|
|
||||||
MutableKeySet ks = keys.remove(k);
|
|
||||||
if (ks == null) throw new IllegalArgumentException();
|
|
||||||
// Check that the keys haven't been bound
|
|
||||||
if (ks.getContactId() != null) throw new IllegalArgumentException();
|
|
||||||
TransportId t = ks.getTransportKeys().getTransportId();
|
|
||||||
db.removeTransportKeys(txn, t, k);
|
|
||||||
} finally {
|
|
||||||
lock.unlock();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void removeContact(ContactId c) {
|
public void removeContact(ContactId c) {
|
||||||
lock.lock();
|
lock.lock();
|
||||||
|
|||||||
@@ -55,8 +55,8 @@ public class ContactManagerImplTest extends BrambleMockTestCase {
|
|||||||
will(returnValue(txn));
|
will(returnValue(txn));
|
||||||
oneOf(db).addContact(txn, remote, local, verified, active);
|
oneOf(db).addContact(txn, remote, local, verified, active);
|
||||||
will(returnValue(contactId));
|
will(returnValue(contactId));
|
||||||
oneOf(keyManager)
|
oneOf(keyManager).addContact(txn, contactId, master, timestamp,
|
||||||
.addContact(txn, contactId, master, timestamp, alice);
|
alice, active);
|
||||||
oneOf(db).getContact(txn, contactId);
|
oneOf(db).getContact(txn, contactId);
|
||||||
will(returnValue(contact));
|
will(returnValue(contact));
|
||||||
oneOf(db).commitTransaction(txn);
|
oneOf(db).commitTransaction(txn);
|
||||||
|
|||||||
@@ -4,13 +4,16 @@ import org.briarproject.bramble.api.FormatException;
|
|||||||
import org.briarproject.bramble.api.data.BdfDictionary;
|
import org.briarproject.bramble.api.data.BdfDictionary;
|
||||||
import org.briarproject.bramble.api.data.BdfList;
|
import org.briarproject.bramble.api.data.BdfList;
|
||||||
import org.briarproject.bramble.test.BrambleTestCase;
|
import org.briarproject.bramble.test.BrambleTestCase;
|
||||||
import org.briarproject.bramble.util.StringUtils;
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
|
|
||||||
import static org.briarproject.bramble.api.data.BdfDictionary.NULL_VALUE;
|
import static org.briarproject.bramble.api.data.BdfDictionary.NULL_VALUE;
|
||||||
|
import static org.briarproject.bramble.api.data.BdfReader.DEFAULT_MAX_BUFFER_SIZE;
|
||||||
import static org.briarproject.bramble.data.BdfReaderImpl.DEFAULT_NESTED_LIMIT;
|
import static org.briarproject.bramble.data.BdfReaderImpl.DEFAULT_NESTED_LIMIT;
|
||||||
|
import static org.briarproject.bramble.util.StringUtils.fromHexString;
|
||||||
|
import static org.briarproject.bramble.util.StringUtils.getRandomString;
|
||||||
|
import static org.briarproject.bramble.util.StringUtils.toHexString;
|
||||||
import static org.junit.Assert.assertArrayEquals;
|
import static org.junit.Assert.assertArrayEquals;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertFalse;
|
import static org.junit.Assert.assertFalse;
|
||||||
@@ -158,30 +161,32 @@ public class BdfReaderImplTest extends BrambleTestCase {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testReadString8() throws Exception {
|
public void testReadString8() throws Exception {
|
||||||
String longest = StringUtils.getRandomString(Byte.MAX_VALUE);
|
String longest = getRandomString(Byte.MAX_VALUE);
|
||||||
String longHex = StringUtils.toHexString(longest.getBytes("UTF-8"));
|
String longHex = toHexString(longest.getBytes("UTF-8"));
|
||||||
// "foo", the empty string, and 127 random letters
|
// "foo", the empty string, and 127 random letters
|
||||||
setContents("41" + "03" + "666F6F" + "41" + "00" +
|
setContents("41" + "03" + "666F6F" + "41" + "00" +
|
||||||
"41" + "7F" + longHex);
|
"41" + "7F" + longHex);
|
||||||
assertEquals("foo", r.readString(Integer.MAX_VALUE));
|
assertEquals("foo", r.readString());
|
||||||
assertEquals("", r.readString(Integer.MAX_VALUE));
|
assertEquals("", r.readString());
|
||||||
assertEquals(longest, r.readString(Integer.MAX_VALUE));
|
assertEquals(longest, r.readString());
|
||||||
assertTrue(r.eof());
|
assertTrue(r.eof());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = FormatException.class)
|
@Test(expected = FormatException.class)
|
||||||
public void testReadString8ChecksMaxLength() throws Exception {
|
public void testReadString8ChecksMaxLength() throws Exception {
|
||||||
// "foo" twice
|
int maxBufferSize = 3;
|
||||||
setContents("41" + "03" + "666F6F" + "41" + "03" + "666F6F");
|
// "foo", "fooo"
|
||||||
assertEquals("foo", r.readString(3));
|
setContents("41" + "03" + "666F6F"
|
||||||
|
+ "41" + "04" + "666F6F6F", maxBufferSize);
|
||||||
|
assertEquals("foo", r.readString());
|
||||||
assertTrue(r.hasString());
|
assertTrue(r.hasString());
|
||||||
r.readString(2);
|
r.readString();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSkipString8() throws Exception {
|
public void testSkipString8() throws Exception {
|
||||||
String longest = StringUtils.getRandomString(Byte.MAX_VALUE);
|
String longest = getRandomString(Byte.MAX_VALUE);
|
||||||
String longHex = StringUtils.toHexString(longest.getBytes("UTF-8"));
|
String longHex = toHexString(longest.getBytes("UTF-8"));
|
||||||
// "foo", the empty string, and 127 random letters
|
// "foo", the empty string, and 127 random letters
|
||||||
setContents("41" + "03" + "666F6F" + "41" + "00" +
|
setContents("41" + "03" + "666F6F" + "41" + "00" +
|
||||||
"41" + "7F" + longHex);
|
"41" + "7F" + longHex);
|
||||||
@@ -193,34 +198,37 @@ public class BdfReaderImplTest extends BrambleTestCase {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testReadString16() throws Exception {
|
public void testReadString16() throws Exception {
|
||||||
String shortest = StringUtils.getRandomString(Byte.MAX_VALUE + 1);
|
String shortest = getRandomString(Byte.MAX_VALUE + 1);
|
||||||
String shortHex = StringUtils.toHexString(shortest.getBytes("UTF-8"));
|
String shortHex = toHexString(shortest.getBytes("UTF-8"));
|
||||||
String longest = StringUtils.getRandomString(Short.MAX_VALUE);
|
String longest = getRandomString(Short.MAX_VALUE);
|
||||||
String longHex = StringUtils.toHexString(longest.getBytes("UTF-8"));
|
String longHex = toHexString(longest.getBytes("UTF-8"));
|
||||||
// 128 random letters and 2^15 -1 random letters
|
// 128 random letters and 2^15 -1 random letters
|
||||||
setContents("42" + "0080" + shortHex + "42" + "7FFF" + longHex);
|
setContents("42" + "0080" + shortHex + "42" + "7FFF" + longHex);
|
||||||
assertEquals(shortest, r.readString(Integer.MAX_VALUE));
|
assertEquals(shortest, r.readString());
|
||||||
assertEquals(longest, r.readString(Integer.MAX_VALUE));
|
assertEquals(longest, r.readString());
|
||||||
assertTrue(r.eof());
|
assertTrue(r.eof());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = FormatException.class)
|
@Test(expected = FormatException.class)
|
||||||
public void testReadString16ChecksMaxLength() throws Exception {
|
public void testReadString16ChecksMaxLength() throws Exception {
|
||||||
String shortest = StringUtils.getRandomString(Byte.MAX_VALUE + 1);
|
int maxBufferSize = Byte.MAX_VALUE + 1;
|
||||||
String shortHex = StringUtils.toHexString(shortest.getBytes("UTF-8"));
|
String valid = getRandomString(Byte.MAX_VALUE + 1);
|
||||||
// 128 random letters, twice
|
String validHex = toHexString(valid.getBytes("UTF-8"));
|
||||||
setContents("42" + "0080" + shortHex + "42" + "0080" + shortHex);
|
String invalidhex = validHex + "20";
|
||||||
assertEquals(shortest, r.readString(Byte.MAX_VALUE + 1));
|
// 128 random letters, the same plus a space
|
||||||
|
setContents("42" + "0080" + validHex
|
||||||
|
+ "42" + "0081" + invalidhex, maxBufferSize);
|
||||||
|
assertEquals(valid, r.readString());
|
||||||
assertTrue(r.hasString());
|
assertTrue(r.hasString());
|
||||||
r.readString(Byte.MAX_VALUE);
|
r.readString();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSkipString16() throws Exception {
|
public void testSkipString16() throws Exception {
|
||||||
String shortest = StringUtils.getRandomString(Byte.MAX_VALUE + 1);
|
String shortest = getRandomString(Byte.MAX_VALUE + 1);
|
||||||
String shortHex = StringUtils.toHexString(shortest.getBytes("UTF-8"));
|
String shortHex = toHexString(shortest.getBytes("UTF-8"));
|
||||||
String longest = StringUtils.getRandomString(Short.MAX_VALUE);
|
String longest = getRandomString(Short.MAX_VALUE);
|
||||||
String longHex = StringUtils.toHexString(longest.getBytes("UTF-8"));
|
String longHex = toHexString(longest.getBytes("UTF-8"));
|
||||||
// 128 random letters and 2^15 - 1 random letters
|
// 128 random letters and 2^15 - 1 random letters
|
||||||
setContents("42" + "0080" + shortHex + "42" + "7FFF" + longHex);
|
setContents("42" + "0080" + shortHex + "42" + "7FFF" + longHex);
|
||||||
r.skipString();
|
r.skipString();
|
||||||
@@ -230,30 +238,32 @@ public class BdfReaderImplTest extends BrambleTestCase {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testReadString32() throws Exception {
|
public void testReadString32() throws Exception {
|
||||||
String shortest = StringUtils.getRandomString(Short.MAX_VALUE + 1);
|
String shortest = getRandomString(Short.MAX_VALUE + 1);
|
||||||
String shortHex = StringUtils.toHexString(shortest.getBytes("UTF-8"));
|
String shortHex = toHexString(shortest.getBytes("UTF-8"));
|
||||||
// 2^15 random letters
|
// 2^15 random letters
|
||||||
setContents("44" + "00008000" + shortHex);
|
setContents("44" + "00008000" + shortHex);
|
||||||
assertEquals(shortest, r.readString(Integer.MAX_VALUE));
|
assertEquals(shortest, r.readString());
|
||||||
assertTrue(r.eof());
|
assertTrue(r.eof());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = FormatException.class)
|
@Test(expected = FormatException.class)
|
||||||
public void testReadString32ChecksMaxLength() throws Exception {
|
public void testReadString32ChecksMaxLength() throws Exception {
|
||||||
String shortest = StringUtils.getRandomString(Short.MAX_VALUE + 1);
|
int maxBufferSize = Short.MAX_VALUE + 1;
|
||||||
String shortHex = StringUtils.toHexString(shortest.getBytes("UTF-8"));
|
String valid = getRandomString(maxBufferSize);
|
||||||
// 2^15 random letters, twice
|
String validHex = toHexString(valid.getBytes("UTF-8"));
|
||||||
setContents("44" + "00008000" + shortHex +
|
String invalidHex = validHex + "20";
|
||||||
"44" + "00008000" + shortHex);
|
// 2^15 random letters, the same plus a space
|
||||||
assertEquals(shortest, r.readString(Short.MAX_VALUE + 1));
|
setContents("44" + "00008000" + validHex +
|
||||||
|
"44" + "00008001" + invalidHex, maxBufferSize);
|
||||||
|
assertEquals(valid, r.readString());
|
||||||
assertTrue(r.hasString());
|
assertTrue(r.hasString());
|
||||||
r.readString(Short.MAX_VALUE);
|
r.readString();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSkipString32() throws Exception {
|
public void testSkipString32() throws Exception {
|
||||||
String shortest = StringUtils.getRandomString(Short.MAX_VALUE + 1);
|
String shortest = getRandomString(Short.MAX_VALUE + 1);
|
||||||
String shortHex = StringUtils.toHexString(shortest.getBytes("UTF-8"));
|
String shortHex = toHexString(shortest.getBytes("UTF-8"));
|
||||||
// 2^15 random letters, twice
|
// 2^15 random letters, twice
|
||||||
setContents("44" + "00008000" + shortHex +
|
setContents("44" + "00008000" + shortHex +
|
||||||
"44" + "00008000" + shortHex);
|
"44" + "00008000" + shortHex);
|
||||||
@@ -265,41 +275,43 @@ public class BdfReaderImplTest extends BrambleTestCase {
|
|||||||
@Test
|
@Test
|
||||||
public void testReadUtf8String() throws Exception {
|
public void testReadUtf8String() throws Exception {
|
||||||
String unicode = "\uFDD0\uFDD1\uFDD2\uFDD3";
|
String unicode = "\uFDD0\uFDD1\uFDD2\uFDD3";
|
||||||
String hex = StringUtils.toHexString(unicode.getBytes("UTF-8"));
|
String hex = toHexString(unicode.getBytes("UTF-8"));
|
||||||
// STRING_8 tag, "foo", the empty string, and the test string
|
// STRING_8 tag, "foo", the empty string, and the test string
|
||||||
setContents("41" + "03" + "666F6F" + "41" + "00" + "41" + "0C" + hex);
|
setContents("41" + "03" + "666F6F" + "41" + "00" + "41" + "0C" + hex);
|
||||||
assertEquals("foo", r.readString(Integer.MAX_VALUE));
|
assertEquals("foo", r.readString());
|
||||||
assertEquals("", r.readString(Integer.MAX_VALUE));
|
assertEquals("", r.readString());
|
||||||
assertEquals(unicode, r.readString(Integer.MAX_VALUE));
|
assertEquals(unicode, r.readString());
|
||||||
assertTrue(r.eof());
|
assertTrue(r.eof());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testReadRaw8() throws Exception {
|
public void testReadRaw8() throws Exception {
|
||||||
byte[] longest = new byte[Byte.MAX_VALUE];
|
byte[] longest = new byte[Byte.MAX_VALUE];
|
||||||
String longHex = StringUtils.toHexString(longest);
|
String longHex = toHexString(longest);
|
||||||
// {1, 2, 3}, {}, and 127 zero bytes
|
// {1, 2, 3}, {}, and 127 zero bytes
|
||||||
setContents("51" + "03" + "010203" + "51" + "00" +
|
setContents("51" + "03" + "010203" + "51" + "00" +
|
||||||
"51" + "7F" + longHex);
|
"51" + "7F" + longHex);
|
||||||
assertArrayEquals(new byte[] {1, 2, 3}, r.readRaw(Integer.MAX_VALUE));
|
assertArrayEquals(new byte[] {1, 2, 3}, r.readRaw());
|
||||||
assertArrayEquals(new byte[0], r.readRaw(Integer.MAX_VALUE));
|
assertArrayEquals(new byte[0], r.readRaw());
|
||||||
assertArrayEquals(longest, r.readRaw(Integer.MAX_VALUE));
|
assertArrayEquals(longest, r.readRaw());
|
||||||
assertTrue(r.eof());
|
assertTrue(r.eof());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = FormatException.class)
|
@Test(expected = FormatException.class)
|
||||||
public void testReadRaw8ChecksMaxLength() throws Exception {
|
public void testReadRaw8ChecksMaxLength() throws Exception {
|
||||||
// {1, 2, 3} twice
|
int maxBufferSize = 3;
|
||||||
setContents("51" + "03" + "010203" + "51" + "03" + "010203");
|
// {1, 2, 3}, {1, 2, 3, 4}
|
||||||
assertArrayEquals(new byte[] {1, 2, 3}, r.readRaw(3));
|
setContents("51" + "03" + "010203" + "51" + "04" + "01020304",
|
||||||
|
maxBufferSize);
|
||||||
|
assertArrayEquals(new byte[] {1, 2, 3}, r.readRaw());
|
||||||
assertTrue(r.hasRaw());
|
assertTrue(r.hasRaw());
|
||||||
r.readRaw(2);
|
r.readRaw();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSkipRaw8() throws Exception {
|
public void testSkipRaw8() throws Exception {
|
||||||
byte[] longest = new byte[Byte.MAX_VALUE];
|
byte[] longest = new byte[Byte.MAX_VALUE];
|
||||||
String longHex = StringUtils.toHexString(longest);
|
String longHex = toHexString(longest);
|
||||||
// {1, 2, 3}, {}, and 127 zero bytes
|
// {1, 2, 3}, {}, and 127 zero bytes
|
||||||
setContents("51" + "03" + "010203" + "51" + "00" +
|
setContents("51" + "03" + "010203" + "51" + "00" +
|
||||||
"51" + "7F" + longHex);
|
"51" + "7F" + longHex);
|
||||||
@@ -312,33 +324,36 @@ public class BdfReaderImplTest extends BrambleTestCase {
|
|||||||
@Test
|
@Test
|
||||||
public void testReadRaw16() throws Exception {
|
public void testReadRaw16() throws Exception {
|
||||||
byte[] shortest = new byte[Byte.MAX_VALUE + 1];
|
byte[] shortest = new byte[Byte.MAX_VALUE + 1];
|
||||||
String shortHex = StringUtils.toHexString(shortest);
|
String shortHex = toHexString(shortest);
|
||||||
byte[] longest = new byte[Short.MAX_VALUE];
|
byte[] longest = new byte[Short.MAX_VALUE];
|
||||||
String longHex = StringUtils.toHexString(longest);
|
String longHex = toHexString(longest);
|
||||||
// 128 zero bytes and 2^15 - 1 zero bytes
|
// 128 zero bytes and 2^15 - 1 zero bytes
|
||||||
setContents("52" + "0080" + shortHex + "52" + "7FFF" + longHex);
|
setContents("52" + "0080" + shortHex + "52" + "7FFF" + longHex);
|
||||||
assertArrayEquals(shortest, r.readRaw(Integer.MAX_VALUE));
|
assertArrayEquals(shortest, r.readRaw());
|
||||||
assertArrayEquals(longest, r.readRaw(Integer.MAX_VALUE));
|
assertArrayEquals(longest, r.readRaw());
|
||||||
assertTrue(r.eof());
|
assertTrue(r.eof());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = FormatException.class)
|
@Test(expected = FormatException.class)
|
||||||
public void testReadRaw16ChecksMaxLength() throws Exception {
|
public void testReadRaw16ChecksMaxLength() throws Exception {
|
||||||
byte[] shortest = new byte[Byte.MAX_VALUE + 1];
|
int maxBufferSize = Byte.MAX_VALUE + 1;
|
||||||
String shortHex = StringUtils.toHexString(shortest);
|
byte[] valid = new byte[maxBufferSize];
|
||||||
// 128 zero bytes, twice
|
String validHex = toHexString(valid);
|
||||||
setContents("52" + "0080" + shortHex + "52" + "0080" + shortHex);
|
String invalidHex = validHex + "00";
|
||||||
assertArrayEquals(shortest, r.readRaw(Byte.MAX_VALUE + 1));
|
// 128 zero bytes, 129 zero bytes
|
||||||
|
setContents("52" + "0080" + validHex
|
||||||
|
+ "52" + "0081" + invalidHex, maxBufferSize);
|
||||||
|
assertArrayEquals(valid, r.readRaw());
|
||||||
assertTrue(r.hasRaw());
|
assertTrue(r.hasRaw());
|
||||||
r.readRaw(Byte.MAX_VALUE);
|
r.readRaw();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSkipRaw16() throws Exception {
|
public void testSkipRaw16() throws Exception {
|
||||||
byte[] shortest = new byte[Byte.MAX_VALUE + 1];
|
byte[] shortest = new byte[Byte.MAX_VALUE + 1];
|
||||||
String shortHex = StringUtils.toHexString(shortest);
|
String shortHex = toHexString(shortest);
|
||||||
byte[] longest = new byte[Short.MAX_VALUE];
|
byte[] longest = new byte[Short.MAX_VALUE];
|
||||||
String longHex = StringUtils.toHexString(longest);
|
String longHex = toHexString(longest);
|
||||||
// 128 zero bytes and 2^15 - 1 zero bytes
|
// 128 zero bytes and 2^15 - 1 zero bytes
|
||||||
setContents("52" + "0080" + shortHex + "52" + "7FFF" + longHex);
|
setContents("52" + "0080" + shortHex + "52" + "7FFF" + longHex);
|
||||||
r.skipRaw();
|
r.skipRaw();
|
||||||
@@ -349,29 +364,31 @@ public class BdfReaderImplTest extends BrambleTestCase {
|
|||||||
@Test
|
@Test
|
||||||
public void testReadRaw32() throws Exception {
|
public void testReadRaw32() throws Exception {
|
||||||
byte[] shortest = new byte[Short.MAX_VALUE + 1];
|
byte[] shortest = new byte[Short.MAX_VALUE + 1];
|
||||||
String shortHex = StringUtils.toHexString(shortest);
|
String shortHex = toHexString(shortest);
|
||||||
// 2^15 zero bytes
|
// 2^15 zero bytes
|
||||||
setContents("54" + "00008000" + shortHex);
|
setContents("54" + "00008000" + shortHex);
|
||||||
assertArrayEquals(shortest, r.readRaw(Integer.MAX_VALUE));
|
assertArrayEquals(shortest, r.readRaw());
|
||||||
assertTrue(r.eof());
|
assertTrue(r.eof());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = FormatException.class)
|
@Test(expected = FormatException.class)
|
||||||
public void testReadRaw32ChecksMaxLength() throws Exception {
|
public void testReadRaw32ChecksMaxLength() throws Exception {
|
||||||
byte[] shortest = new byte[Short.MAX_VALUE + 1];
|
int maxBufferSize = Short.MAX_VALUE + 1;
|
||||||
String shortHex = StringUtils.toHexString(shortest);
|
byte[] valid = new byte[maxBufferSize];
|
||||||
// 2^15 zero bytes, twice
|
String validHex = toHexString(valid);
|
||||||
setContents("54" + "00008000" + shortHex +
|
String invalidHex = validHex + "00";
|
||||||
"54" + "00008000" + shortHex);
|
// 2^15 zero bytes, 2^15 + 1 zero bytes
|
||||||
assertArrayEquals(shortest, r.readRaw(Short.MAX_VALUE + 1));
|
setContents("54" + "00008000" + validHex +
|
||||||
|
"54" + "00008001" + invalidHex, maxBufferSize);
|
||||||
|
assertArrayEquals(valid, r.readRaw());
|
||||||
assertTrue(r.hasRaw());
|
assertTrue(r.hasRaw());
|
||||||
r.readRaw(Short.MAX_VALUE);
|
r.readRaw();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSkipRaw32() throws Exception {
|
public void testSkipRaw32() throws Exception {
|
||||||
byte[] shortest = new byte[Short.MAX_VALUE + 1];
|
byte[] shortest = new byte[Short.MAX_VALUE + 1];
|
||||||
String shortHex = StringUtils.toHexString(shortest);
|
String shortHex = toHexString(shortest);
|
||||||
// 2^15 zero bytes, twice
|
// 2^15 zero bytes, twice
|
||||||
setContents("54" + "00008000" + shortHex +
|
setContents("54" + "00008000" + shortHex +
|
||||||
"54" + "00008000" + shortHex);
|
"54" + "00008000" + shortHex);
|
||||||
@@ -393,6 +410,30 @@ public class BdfReaderImplTest extends BrambleTestCase {
|
|||||||
assertEquals(NULL_VALUE, list.get(2));
|
assertEquals(NULL_VALUE, list.get(2));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test(expected = FormatException.class)
|
||||||
|
public void testReadListChecksMaxLengthForString() throws Exception {
|
||||||
|
// A list containing "foo", a list containing "fooo"
|
||||||
|
setContents("60" + "41" + "03" + "666F6F" + "80"
|
||||||
|
+ "60" + "41" + "04" + "666F6F6F" + "80", 3);
|
||||||
|
BdfList list = r.readList();
|
||||||
|
assertEquals(1, list.size());
|
||||||
|
assertEquals("foo", list.get(0));
|
||||||
|
assertTrue(r.hasList());
|
||||||
|
r.readList();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = FormatException.class)
|
||||||
|
public void testReadListChecksMaxLengthForRaw() throws Exception {
|
||||||
|
// A list containing {1, 2, 3}, a list containing {1, 2, 3, 4}
|
||||||
|
setContents("60" + "51" + "03" + "010203" + "80"
|
||||||
|
+ "60" + "51" + "04" + "01020304" + "80", 3);
|
||||||
|
BdfList list = r.readList();
|
||||||
|
assertEquals(1, list.size());
|
||||||
|
assertArrayEquals(new byte[] {1, 2, 3}, (byte[]) list.get(0));
|
||||||
|
assertTrue(r.hasList());
|
||||||
|
r.readList();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testReadListManually() throws Exception {
|
public void testReadListManually() throws Exception {
|
||||||
// A list containing 1, "foo", and null
|
// A list containing 1, "foo", and null
|
||||||
@@ -403,7 +444,7 @@ public class BdfReaderImplTest extends BrambleTestCase {
|
|||||||
assertFalse(r.hasListEnd());
|
assertFalse(r.hasListEnd());
|
||||||
assertEquals(1, r.readLong());
|
assertEquals(1, r.readLong());
|
||||||
assertFalse(r.hasListEnd());
|
assertFalse(r.hasListEnd());
|
||||||
assertEquals("foo", r.readString(1000));
|
assertEquals("foo", r.readString());
|
||||||
assertFalse(r.hasListEnd());
|
assertFalse(r.hasListEnd());
|
||||||
assertTrue(r.hasNull());
|
assertTrue(r.hasNull());
|
||||||
r.readNull();
|
r.readNull();
|
||||||
@@ -435,6 +476,47 @@ public class BdfReaderImplTest extends BrambleTestCase {
|
|||||||
assertEquals(NULL_VALUE, dictionary.get("bar"));
|
assertEquals(NULL_VALUE, dictionary.get("bar"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test(expected = FormatException.class)
|
||||||
|
public void testReadDictionaryChecksMaxLengthForKey() throws Exception {
|
||||||
|
// A dictionary containing "foo" -> null, a dictionary containing
|
||||||
|
// "fooo" -> null
|
||||||
|
setContents("70" + "41" + "03" + "666F6F" + "00" + "80"
|
||||||
|
+ "70" + "41" + "04" + "666F6F6F" + "00" + "80", 3);
|
||||||
|
BdfDictionary dictionary = r.readDictionary();
|
||||||
|
assertEquals(1, dictionary.size());
|
||||||
|
assertEquals(NULL_VALUE, dictionary.get("foo"));
|
||||||
|
assertTrue(r.hasDictionary());
|
||||||
|
r.readDictionary();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = FormatException.class)
|
||||||
|
public void testReadDictionaryChecksMaxLengthForString() throws Exception {
|
||||||
|
// A dictionary containing "foo" -> "bar", a dictionary containing
|
||||||
|
// "foo" -> "baar"
|
||||||
|
String foo = "41" + "03" + "666F6F";
|
||||||
|
setContents("70" + foo + "41" + "03" + "626172" + "80"
|
||||||
|
+ "70" + foo + "41" + "04" + "62616172" + "80", 3);
|
||||||
|
BdfDictionary dictionary = r.readDictionary();
|
||||||
|
assertEquals(1, dictionary.size());
|
||||||
|
assertEquals("bar", dictionary.get("foo"));
|
||||||
|
assertTrue(r.hasDictionary());
|
||||||
|
r.readDictionary();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = FormatException.class)
|
||||||
|
public void testReadDictionaryChecksMaxLengthForRaw() throws Exception {
|
||||||
|
// A dictionary containing "foo" -> {1, 2, 3}, a dictionary containing
|
||||||
|
// "foo" -> {1, 2, 3, 4}
|
||||||
|
String foo = "41" + "03" + "666F6F";
|
||||||
|
setContents("70" + foo + "51" + "03" + "010203" + "80"
|
||||||
|
+ "70" + foo + "51" + "04" + "01020304" + "80", 3);
|
||||||
|
BdfDictionary dictionary = r.readDictionary();
|
||||||
|
assertEquals(1, dictionary.size());
|
||||||
|
assertArrayEquals(new byte[] {1, 2, 3}, (byte[]) dictionary.get("foo"));
|
||||||
|
assertTrue(r.hasDictionary());
|
||||||
|
r.readDictionary();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testReadDictionaryManually() throws Exception {
|
public void testReadDictionaryManually() throws Exception {
|
||||||
// A dictionary containing "foo" -> 123 and "bar" -> null
|
// A dictionary containing "foo" -> 123 and "bar" -> null
|
||||||
@@ -442,11 +524,11 @@ public class BdfReaderImplTest extends BrambleTestCase {
|
|||||||
"41" + "03" + "626172" + "00" + "80");
|
"41" + "03" + "626172" + "00" + "80");
|
||||||
r.readDictionaryStart();
|
r.readDictionaryStart();
|
||||||
assertFalse(r.hasDictionaryEnd());
|
assertFalse(r.hasDictionaryEnd());
|
||||||
assertEquals("foo", r.readString(1000));
|
assertEquals("foo", r.readString());
|
||||||
assertFalse(r.hasDictionaryEnd());
|
assertFalse(r.hasDictionaryEnd());
|
||||||
assertEquals(123, r.readLong());
|
assertEquals(123, r.readLong());
|
||||||
assertFalse(r.hasDictionaryEnd());
|
assertFalse(r.hasDictionaryEnd());
|
||||||
assertEquals("bar", r.readString(1000));
|
assertEquals("bar", r.readString());
|
||||||
assertFalse(r.hasDictionaryEnd());
|
assertFalse(r.hasDictionaryEnd());
|
||||||
assertTrue(r.hasNull());
|
assertTrue(r.hasNull());
|
||||||
r.readNull();
|
r.readNull();
|
||||||
@@ -537,8 +619,11 @@ public class BdfReaderImplTest extends BrambleTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void setContents(String hex) {
|
private void setContents(String hex) {
|
||||||
ByteArrayInputStream in = new ByteArrayInputStream(
|
setContents(hex, DEFAULT_MAX_BUFFER_SIZE);
|
||||||
StringUtils.fromHexString(hex));
|
}
|
||||||
r = new BdfReaderImpl(in, DEFAULT_NESTED_LIMIT);
|
|
||||||
|
private void setContents(String hex, int maxBufferSize) {
|
||||||
|
ByteArrayInputStream in = new ByteArrayInputStream(fromHexString(hex));
|
||||||
|
r = new BdfReaderImpl(in, DEFAULT_NESTED_LIMIT, maxBufferSize);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -289,11 +289,11 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
|
|||||||
throws Exception {
|
throws Exception {
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
// Check whether the contact is in the DB (which it's not)
|
// Check whether the contact is in the DB (which it's not)
|
||||||
exactly(17).of(database).startTransaction();
|
exactly(16).of(database).startTransaction();
|
||||||
will(returnValue(txn));
|
will(returnValue(txn));
|
||||||
exactly(17).of(database).containsContact(txn, contactId);
|
exactly(16).of(database).containsContact(txn, contactId);
|
||||||
will(returnValue(false));
|
will(returnValue(false));
|
||||||
exactly(17).of(database).abortTransaction(txn);
|
exactly(16).of(database).abortTransaction(txn);
|
||||||
}});
|
}});
|
||||||
DatabaseComponent db = createDatabaseComponent(database, eventBus,
|
DatabaseComponent db = createDatabaseComponent(database, eventBus,
|
||||||
shutdown);
|
shutdown);
|
||||||
@@ -308,16 +308,6 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
|
|||||||
db.endTransaction(transaction);
|
db.endTransaction(transaction);
|
||||||
}
|
}
|
||||||
|
|
||||||
transaction = db.startTransaction(false);
|
|
||||||
try {
|
|
||||||
db.bindTransportKeys(transaction, contactId, transportId, keySetId);
|
|
||||||
fail();
|
|
||||||
} catch (NoSuchContactException expected) {
|
|
||||||
// Expected
|
|
||||||
} finally {
|
|
||||||
db.endTransaction(transaction);
|
|
||||||
}
|
|
||||||
|
|
||||||
transaction = db.startTransaction(false);
|
transaction = db.startTransaction(false);
|
||||||
try {
|
try {
|
||||||
db.generateAck(transaction, contactId, 123);
|
db.generateAck(transaction, contactId, 123);
|
||||||
@@ -773,13 +763,11 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
|
|||||||
// endTransaction()
|
// endTransaction()
|
||||||
oneOf(database).commitTransaction(txn);
|
oneOf(database).commitTransaction(txn);
|
||||||
// Check whether the transport is in the DB (which it's not)
|
// Check whether the transport is in the DB (which it's not)
|
||||||
exactly(6).of(database).startTransaction();
|
exactly(5).of(database).startTransaction();
|
||||||
will(returnValue(txn));
|
will(returnValue(txn));
|
||||||
oneOf(database).containsContact(txn, contactId);
|
exactly(5).of(database).containsTransport(txn, transportId);
|
||||||
will(returnValue(true));
|
|
||||||
exactly(6).of(database).containsTransport(txn, transportId);
|
|
||||||
will(returnValue(false));
|
will(returnValue(false));
|
||||||
exactly(6).of(database).abortTransaction(txn);
|
exactly(5).of(database).abortTransaction(txn);
|
||||||
}});
|
}});
|
||||||
DatabaseComponent db = createDatabaseComponent(database, eventBus,
|
DatabaseComponent db = createDatabaseComponent(database, eventBus,
|
||||||
shutdown);
|
shutdown);
|
||||||
@@ -794,16 +782,6 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
|
|||||||
db.endTransaction(transaction);
|
db.endTransaction(transaction);
|
||||||
}
|
}
|
||||||
|
|
||||||
transaction = db.startTransaction(false);
|
|
||||||
try {
|
|
||||||
db.bindTransportKeys(transaction, contactId, transportId, keySetId);
|
|
||||||
fail();
|
|
||||||
} catch (NoSuchTransportException expected) {
|
|
||||||
// Expected
|
|
||||||
} finally {
|
|
||||||
db.endTransaction(transaction);
|
|
||||||
}
|
|
||||||
|
|
||||||
transaction = db.startTransaction(false);
|
transaction = db.startTransaction(false);
|
||||||
try {
|
try {
|
||||||
db.getTransportKeys(transaction, transportId);
|
db.getTransportKeys(transaction, transportId);
|
||||||
|
|||||||
@@ -94,6 +94,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
|
|||||||
private final TransportId transportId;
|
private final TransportId transportId;
|
||||||
private final ContactId contactId;
|
private final ContactId contactId;
|
||||||
private final KeySetId keySetId, keySetId1;
|
private final KeySetId keySetId, keySetId1;
|
||||||
|
private final Random random = new Random();
|
||||||
|
|
||||||
JdbcDatabaseTest() throws Exception {
|
JdbcDatabaseTest() throws Exception {
|
||||||
clientId = getClientId();
|
clientId = getClientId();
|
||||||
@@ -670,8 +671,9 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
|
|||||||
@Test
|
@Test
|
||||||
public void testTransportKeys() throws Exception {
|
public void testTransportKeys() throws Exception {
|
||||||
long rotationPeriod = 123, rotationPeriod1 = 234;
|
long rotationPeriod = 123, rotationPeriod1 = 234;
|
||||||
TransportKeys keys = createTransportKeys(rotationPeriod);
|
boolean active = random.nextBoolean();
|
||||||
TransportKeys keys1 = createTransportKeys(rotationPeriod1);
|
TransportKeys keys = createTransportKeys(rotationPeriod, active);
|
||||||
|
TransportKeys keys1 = createTransportKeys(rotationPeriod1, active);
|
||||||
|
|
||||||
Database<Connection> db = open(false);
|
Database<Connection> db = open(false);
|
||||||
Connection txn = db.startTransaction();
|
Connection txn = db.startTransaction();
|
||||||
@@ -682,7 +684,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
|
|||||||
// Add the contact, the transport and the transport keys
|
// Add the contact, the transport and the transport keys
|
||||||
db.addLocalAuthor(txn, localAuthor);
|
db.addLocalAuthor(txn, localAuthor);
|
||||||
assertEquals(contactId, db.addContact(txn, author, localAuthor.getId(),
|
assertEquals(contactId, db.addContact(txn, author, localAuthor.getId(),
|
||||||
true, true));
|
true, active));
|
||||||
db.addTransport(txn, transportId, 123);
|
db.addTransport(txn, transportId, 123);
|
||||||
assertEquals(keySetId, db.addTransportKeys(txn, contactId, keys));
|
assertEquals(keySetId, db.addTransportKeys(txn, contactId, keys));
|
||||||
assertEquals(keySetId1, db.addTransportKeys(txn, contactId, keys1));
|
assertEquals(keySetId1, db.addTransportKeys(txn, contactId, keys1));
|
||||||
@@ -701,8 +703,9 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Rotate the transport keys
|
// Rotate the transport keys
|
||||||
TransportKeys rotated = createTransportKeys(rotationPeriod + 1);
|
TransportKeys rotated = createTransportKeys(rotationPeriod + 1, active);
|
||||||
TransportKeys rotated1 = createTransportKeys(rotationPeriod1 + 1);
|
TransportKeys rotated1 =
|
||||||
|
createTransportKeys(rotationPeriod1 + 1, active);
|
||||||
db.updateTransportKeys(txn, new KeySet(keySetId, contactId, rotated));
|
db.updateTransportKeys(txn, new KeySet(keySetId, contactId, rotated));
|
||||||
db.updateTransportKeys(txn, new KeySet(keySetId1, contactId, rotated1));
|
db.updateTransportKeys(txn, new KeySet(keySetId1, contactId, rotated1));
|
||||||
|
|
||||||
@@ -727,95 +730,6 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
|
|||||||
db.close();
|
db.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testUnboundTransportKeys() throws Exception {
|
|
||||||
long rotationPeriod = 123, rotationPeriod1 = 234;
|
|
||||||
TransportKeys keys = createTransportKeys(rotationPeriod);
|
|
||||||
TransportKeys keys1 = createTransportKeys(rotationPeriod1);
|
|
||||||
|
|
||||||
Database<Connection> db = open(false);
|
|
||||||
Connection txn = db.startTransaction();
|
|
||||||
|
|
||||||
// Initially there should be no transport keys in the database
|
|
||||||
assertEquals(emptyList(), db.getTransportKeys(txn, transportId));
|
|
||||||
|
|
||||||
// Add the contact, the transport and the unbound transport keys
|
|
||||||
db.addLocalAuthor(txn, localAuthor);
|
|
||||||
assertEquals(contactId, db.addContact(txn, author, localAuthor.getId(),
|
|
||||||
true, true));
|
|
||||||
db.addTransport(txn, transportId, 123);
|
|
||||||
assertEquals(keySetId, db.addTransportKeys(txn, null, keys));
|
|
||||||
assertEquals(keySetId1, db.addTransportKeys(txn, null, keys1));
|
|
||||||
|
|
||||||
// Retrieve the transport keys
|
|
||||||
Collection<KeySet> allKeys = db.getTransportKeys(txn, transportId);
|
|
||||||
assertEquals(2, allKeys.size());
|
|
||||||
for (KeySet ks : allKeys) {
|
|
||||||
assertNull(ks.getContactId());
|
|
||||||
if (ks.getKeySetId().equals(keySetId)) {
|
|
||||||
assertKeysEquals(keys, ks.getTransportKeys());
|
|
||||||
} else {
|
|
||||||
assertEquals(keySetId1, ks.getKeySetId());
|
|
||||||
assertKeysEquals(keys1, ks.getTransportKeys());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Bind the first set of transport keys
|
|
||||||
db.bindTransportKeys(txn, contactId, transportId, keySetId);
|
|
||||||
|
|
||||||
// Retrieve the keys again - the first set should be bound
|
|
||||||
allKeys = db.getTransportKeys(txn, transportId);
|
|
||||||
assertEquals(2, allKeys.size());
|
|
||||||
for (KeySet ks : allKeys) {
|
|
||||||
if (ks.getKeySetId().equals(keySetId)) {
|
|
||||||
assertEquals(contactId, ks.getContactId());
|
|
||||||
assertKeysEquals(keys, ks.getTransportKeys());
|
|
||||||
} else {
|
|
||||||
assertEquals(keySetId1, ks.getKeySetId());
|
|
||||||
assertNull(ks.getContactId());
|
|
||||||
assertKeysEquals(keys1, ks.getTransportKeys());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Rotate the transport keys
|
|
||||||
TransportKeys rotated = createTransportKeys(rotationPeriod + 1);
|
|
||||||
TransportKeys rotated1 = createTransportKeys(rotationPeriod1 + 1);
|
|
||||||
db.updateTransportKeys(txn, new KeySet(keySetId, contactId, rotated));
|
|
||||||
db.updateTransportKeys(txn, new KeySet(keySetId1, null, rotated1));
|
|
||||||
|
|
||||||
// Retrieve the transport keys again
|
|
||||||
allKeys = db.getTransportKeys(txn, transportId);
|
|
||||||
assertEquals(2, allKeys.size());
|
|
||||||
for (KeySet ks : allKeys) {
|
|
||||||
if (ks.getKeySetId().equals(keySetId)) {
|
|
||||||
assertEquals(contactId, ks.getContactId());
|
|
||||||
assertKeysEquals(rotated, ks.getTransportKeys());
|
|
||||||
} else {
|
|
||||||
assertEquals(keySetId1, ks.getKeySetId());
|
|
||||||
assertNull(ks.getContactId());
|
|
||||||
assertKeysEquals(rotated1, ks.getTransportKeys());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove the unbound transport keys
|
|
||||||
db.removeTransportKeys(txn, transportId, keySetId1);
|
|
||||||
|
|
||||||
// Retrieve the keys again - the second set should be gone
|
|
||||||
allKeys = db.getTransportKeys(txn, transportId);
|
|
||||||
assertEquals(1, allKeys.size());
|
|
||||||
KeySet ks = allKeys.iterator().next();
|
|
||||||
assertEquals(keySetId, ks.getKeySetId());
|
|
||||||
assertEquals(contactId, ks.getContactId());
|
|
||||||
assertKeysEquals(rotated, ks.getTransportKeys());
|
|
||||||
|
|
||||||
// Removing the transport should remove the remaining transport keys
|
|
||||||
db.removeTransport(txn, transportId);
|
|
||||||
assertEquals(emptyList(), db.getTransportKeys(txn, transportId));
|
|
||||||
|
|
||||||
db.commitTransaction(txn);
|
|
||||||
db.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void assertKeysEquals(TransportKeys expected,
|
private void assertKeysEquals(TransportKeys expected,
|
||||||
TransportKeys actual) {
|
TransportKeys actual) {
|
||||||
assertEquals(expected.getTransportId(), actual.getTransportId());
|
assertEquals(expected.getTransportId(), actual.getTransportId());
|
||||||
@@ -853,7 +767,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
|
|||||||
@Test
|
@Test
|
||||||
public void testIncrementStreamCounter() throws Exception {
|
public void testIncrementStreamCounter() throws Exception {
|
||||||
long rotationPeriod = 123;
|
long rotationPeriod = 123;
|
||||||
TransportKeys keys = createTransportKeys(rotationPeriod);
|
TransportKeys keys = createTransportKeys(rotationPeriod, true);
|
||||||
long streamCounter = keys.getCurrentOutgoingKeys().getStreamCounter();
|
long streamCounter = keys.getCurrentOutgoingKeys().getStreamCounter();
|
||||||
|
|
||||||
Database<Connection> db = open(false);
|
Database<Connection> db = open(false);
|
||||||
@@ -893,8 +807,9 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSetReorderingWindow() throws Exception {
|
public void testSetReorderingWindow() throws Exception {
|
||||||
|
boolean active = random.nextBoolean();
|
||||||
long rotationPeriod = 123;
|
long rotationPeriod = 123;
|
||||||
TransportKeys keys = createTransportKeys(rotationPeriod);
|
TransportKeys keys = createTransportKeys(rotationPeriod, active);
|
||||||
long base = keys.getCurrentIncomingKeys().getWindowBase();
|
long base = keys.getCurrentIncomingKeys().getWindowBase();
|
||||||
byte[] bitmap = keys.getCurrentIncomingKeys().getWindowBitmap();
|
byte[] bitmap = keys.getCurrentIncomingKeys().getWindowBitmap();
|
||||||
|
|
||||||
@@ -904,12 +819,12 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
|
|||||||
// Add the contact, transport and transport keys
|
// Add the contact, transport and transport keys
|
||||||
db.addLocalAuthor(txn, localAuthor);
|
db.addLocalAuthor(txn, localAuthor);
|
||||||
assertEquals(contactId, db.addContact(txn, author, localAuthor.getId(),
|
assertEquals(contactId, db.addContact(txn, author, localAuthor.getId(),
|
||||||
true, true));
|
true, active));
|
||||||
db.addTransport(txn, transportId, 123);
|
db.addTransport(txn, transportId, 123);
|
||||||
assertEquals(keySetId, db.addTransportKeys(txn, contactId, keys));
|
assertEquals(keySetId, db.addTransportKeys(txn, contactId, keys));
|
||||||
|
|
||||||
// Update the reordering window and retrieve the transport keys
|
// Update the reordering window and retrieve the transport keys
|
||||||
new Random().nextBytes(bitmap);
|
random.nextBytes(bitmap);
|
||||||
db.setReorderingWindow(txn, keySetId, transportId, rotationPeriod,
|
db.setReorderingWindow(txn, keySetId, transportId, rotationPeriod,
|
||||||
base + 1, bitmap);
|
base + 1, bitmap);
|
||||||
Collection<KeySet> newKeys = db.getTransportKeys(txn, transportId);
|
Collection<KeySet> newKeys = db.getTransportKeys(txn, transportId);
|
||||||
@@ -1908,7 +1823,8 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
|
|||||||
return db;
|
return db;
|
||||||
}
|
}
|
||||||
|
|
||||||
private TransportKeys createTransportKeys(long rotationPeriod) {
|
private TransportKeys createTransportKeys(long rotationPeriod,
|
||||||
|
boolean active) {
|
||||||
SecretKey inPrevTagKey = getSecretKey();
|
SecretKey inPrevTagKey = getSecretKey();
|
||||||
SecretKey inPrevHeaderKey = getSecretKey();
|
SecretKey inPrevHeaderKey = getSecretKey();
|
||||||
IncomingKeys inPrev = new IncomingKeys(inPrevTagKey, inPrevHeaderKey,
|
IncomingKeys inPrev = new IncomingKeys(inPrevTagKey, inPrevHeaderKey,
|
||||||
@@ -1924,7 +1840,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
|
|||||||
SecretKey outCurrTagKey = getSecretKey();
|
SecretKey outCurrTagKey = getSecretKey();
|
||||||
SecretKey outCurrHeaderKey = getSecretKey();
|
SecretKey outCurrHeaderKey = getSecretKey();
|
||||||
OutgoingKeys outCurr = new OutgoingKeys(outCurrTagKey, outCurrHeaderKey,
|
OutgoingKeys outCurr = new OutgoingKeys(outCurrTagKey, outCurrHeaderKey,
|
||||||
rotationPeriod, 456, true);
|
rotationPeriod, 456, active);
|
||||||
return new TransportKeys(transportId, inPrev, inCurr, inNext, outCurr);
|
return new TransportKeys(transportId, inPrev, inCurr, inNext, outCurr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package org.briarproject.bramble.plugin;
|
|||||||
|
|
||||||
import org.briarproject.bramble.api.event.EventBus;
|
import org.briarproject.bramble.api.event.EventBus;
|
||||||
import org.briarproject.bramble.api.plugin.ConnectionManager;
|
import org.briarproject.bramble.api.plugin.ConnectionManager;
|
||||||
|
import org.briarproject.bramble.api.plugin.ConnectionRegistry;
|
||||||
import org.briarproject.bramble.api.plugin.PluginConfig;
|
import org.briarproject.bramble.api.plugin.PluginConfig;
|
||||||
import org.briarproject.bramble.api.plugin.PluginException;
|
import org.briarproject.bramble.api.plugin.PluginException;
|
||||||
import org.briarproject.bramble.api.plugin.TransportId;
|
import org.briarproject.bramble.api.plugin.TransportId;
|
||||||
@@ -13,16 +14,18 @@ import org.briarproject.bramble.api.plugin.simplex.SimplexPluginCallback;
|
|||||||
import org.briarproject.bramble.api.plugin.simplex.SimplexPluginFactory;
|
import org.briarproject.bramble.api.plugin.simplex.SimplexPluginFactory;
|
||||||
import org.briarproject.bramble.api.properties.TransportPropertyManager;
|
import org.briarproject.bramble.api.properties.TransportPropertyManager;
|
||||||
import org.briarproject.bramble.api.settings.SettingsManager;
|
import org.briarproject.bramble.api.settings.SettingsManager;
|
||||||
import org.briarproject.bramble.api.ui.UiCallback;
|
import org.briarproject.bramble.api.system.Clock;
|
||||||
import org.briarproject.bramble.test.BrambleTestCase;
|
import org.briarproject.bramble.test.BrambleTestCase;
|
||||||
import org.jmock.Expectations;
|
import org.jmock.Expectations;
|
||||||
import org.jmock.Mockery;
|
import org.jmock.Mockery;
|
||||||
import org.jmock.lib.concurrent.Synchroniser;
|
import org.jmock.lib.concurrent.Synchroniser;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.security.SecureRandom;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
|
|
||||||
import static org.briarproject.bramble.test.TestUtils.getTransportId;
|
import static org.briarproject.bramble.test.TestUtils.getTransportId;
|
||||||
|
|
||||||
@@ -34,15 +37,20 @@ public class PluginManagerImplTest extends BrambleTestCase {
|
|||||||
setThreadingPolicy(new Synchroniser());
|
setThreadingPolicy(new Synchroniser());
|
||||||
}};
|
}};
|
||||||
Executor ioExecutor = Executors.newSingleThreadExecutor();
|
Executor ioExecutor = Executors.newSingleThreadExecutor();
|
||||||
|
ScheduledExecutorService scheduler =
|
||||||
|
context.mock(ScheduledExecutorService.class);
|
||||||
|
SecureRandom random = new SecureRandom();
|
||||||
|
Clock clock = context.mock(Clock.class);
|
||||||
EventBus eventBus = context.mock(EventBus.class);
|
EventBus eventBus = context.mock(EventBus.class);
|
||||||
PluginConfig pluginConfig = context.mock(PluginConfig.class);
|
PluginConfig pluginConfig = context.mock(PluginConfig.class);
|
||||||
ConnectionManager connectionManager =
|
ConnectionManager connectionManager =
|
||||||
context.mock(ConnectionManager.class);
|
context.mock(ConnectionManager.class);
|
||||||
|
ConnectionRegistry connectionRegistry =
|
||||||
|
context.mock(ConnectionRegistry.class);
|
||||||
SettingsManager settingsManager =
|
SettingsManager settingsManager =
|
||||||
context.mock(SettingsManager.class);
|
context.mock(SettingsManager.class);
|
||||||
TransportPropertyManager transportPropertyManager =
|
TransportPropertyManager transportPropertyManager =
|
||||||
context.mock(TransportPropertyManager.class);
|
context.mock(TransportPropertyManager.class);
|
||||||
UiCallback uiCallback = context.mock(UiCallback.class);
|
|
||||||
|
|
||||||
// Two simplex plugin factories: both create plugins, one fails to start
|
// Two simplex plugin factories: both create plugins, one fails to start
|
||||||
SimplexPluginFactory simplexFactory =
|
SimplexPluginFactory simplexFactory =
|
||||||
@@ -71,6 +79,8 @@ public class PluginManagerImplTest extends BrambleTestCase {
|
|||||||
will(returnValue(simplexFailId));
|
will(returnValue(simplexFailId));
|
||||||
allowing(duplexPlugin).getId();
|
allowing(duplexPlugin).getId();
|
||||||
will(returnValue(duplexId));
|
will(returnValue(duplexId));
|
||||||
|
allowing(pluginConfig).shouldPoll();
|
||||||
|
will(returnValue(false));
|
||||||
// start()
|
// start()
|
||||||
// First simplex plugin
|
// First simplex plugin
|
||||||
oneOf(pluginConfig).getSimplexFactories();
|
oneOf(pluginConfig).getSimplexFactories();
|
||||||
@@ -112,9 +122,9 @@ public class PluginManagerImplTest extends BrambleTestCase {
|
|||||||
oneOf(duplexPlugin).stop();
|
oneOf(duplexPlugin).stop();
|
||||||
}});
|
}});
|
||||||
|
|
||||||
PluginManagerImpl p = new PluginManagerImpl(ioExecutor, eventBus,
|
PluginManagerImpl p = new PluginManagerImpl(ioExecutor, scheduler,
|
||||||
pluginConfig, connectionManager, settingsManager,
|
eventBus, pluginConfig, connectionManager, connectionRegistry,
|
||||||
transportPropertyManager, uiCallback);
|
settingsManager, transportPropertyManager, random, clock);
|
||||||
|
|
||||||
// Two plugins should be started and stopped
|
// Two plugins should be started and stopped
|
||||||
p.startService();
|
p.startService();
|
||||||
|
|||||||
@@ -15,6 +15,8 @@ import org.briarproject.bramble.api.plugin.event.ConnectionOpenedEvent;
|
|||||||
import org.briarproject.bramble.api.plugin.event.TransportDisabledEvent;
|
import org.briarproject.bramble.api.plugin.event.TransportDisabledEvent;
|
||||||
import org.briarproject.bramble.api.plugin.event.TransportEnabledEvent;
|
import org.briarproject.bramble.api.plugin.event.TransportEnabledEvent;
|
||||||
import org.briarproject.bramble.api.plugin.simplex.SimplexPlugin;
|
import org.briarproject.bramble.api.plugin.simplex.SimplexPlugin;
|
||||||
|
import org.briarproject.bramble.api.properties.TransportProperties;
|
||||||
|
import org.briarproject.bramble.api.properties.TransportPropertyManager;
|
||||||
import org.briarproject.bramble.api.system.Clock;
|
import org.briarproject.bramble.api.system.Clock;
|
||||||
import org.briarproject.bramble.test.BrambleMockTestCase;
|
import org.briarproject.bramble.test.BrambleMockTestCase;
|
||||||
import org.briarproject.bramble.test.ImmediateExecutor;
|
import org.briarproject.bramble.test.ImmediateExecutor;
|
||||||
@@ -24,13 +26,15 @@ import org.jmock.lib.legacy.ClassImposteriser;
|
|||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import java.security.SecureRandom;
|
import java.security.SecureRandom;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
import java.util.concurrent.ScheduledExecutorService;
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
import java.util.concurrent.ScheduledFuture;
|
import java.util.concurrent.ScheduledFuture;
|
||||||
|
|
||||||
|
import static java.util.Arrays.asList;
|
||||||
|
import static java.util.Collections.emptyList;
|
||||||
|
import static java.util.Collections.singletonList;
|
||||||
|
import static java.util.Collections.singletonMap;
|
||||||
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
||||||
import static org.briarproject.bramble.test.TestUtils.getTransportId;
|
import static org.briarproject.bramble.test.TestUtils.getTransportId;
|
||||||
|
|
||||||
@@ -44,6 +48,8 @@ public class PollerTest extends BrambleMockTestCase {
|
|||||||
context.mock(ConnectionRegistry.class);
|
context.mock(ConnectionRegistry.class);
|
||||||
private final PluginManager pluginManager =
|
private final PluginManager pluginManager =
|
||||||
context.mock(PluginManager.class);
|
context.mock(PluginManager.class);
|
||||||
|
private final TransportPropertyManager transportPropertyManager =
|
||||||
|
context.mock(TransportPropertyManager.class);
|
||||||
private final Clock clock = context.mock(Clock.class);
|
private final Clock clock = context.mock(Clock.class);
|
||||||
private final ScheduledFuture future = context.mock(ScheduledFuture.class);
|
private final ScheduledFuture future = context.mock(ScheduledFuture.class);
|
||||||
private final SecureRandom random;
|
private final SecureRandom random;
|
||||||
@@ -51,6 +57,7 @@ public class PollerTest extends BrambleMockTestCase {
|
|||||||
private final Executor ioExecutor = new ImmediateExecutor();
|
private final Executor ioExecutor = new ImmediateExecutor();
|
||||||
private final TransportId transportId = getTransportId();
|
private final TransportId transportId = getTransportId();
|
||||||
private final ContactId contactId = new ContactId(234);
|
private final ContactId contactId = new ContactId(234);
|
||||||
|
private final TransportProperties properties = new TransportProperties();
|
||||||
private final int pollingInterval = 60 * 1000;
|
private final int pollingInterval = 60 * 1000;
|
||||||
private final long now = System.currentTimeMillis();
|
private final long now = System.currentTimeMillis();
|
||||||
|
|
||||||
@@ -66,8 +73,8 @@ public class PollerTest extends BrambleMockTestCase {
|
|||||||
SimplexPlugin simplexPlugin1 =
|
SimplexPlugin simplexPlugin1 =
|
||||||
context.mock(SimplexPlugin.class, "simplexPlugin1");
|
context.mock(SimplexPlugin.class, "simplexPlugin1");
|
||||||
TransportId simplexId1 = getTransportId();
|
TransportId simplexId1 = getTransportId();
|
||||||
List<SimplexPlugin> simplexPlugins = Arrays.asList(simplexPlugin,
|
List<SimplexPlugin> simplexPlugins =
|
||||||
simplexPlugin1);
|
asList(simplexPlugin, simplexPlugin1);
|
||||||
TransportConnectionWriter simplexWriter =
|
TransportConnectionWriter simplexWriter =
|
||||||
context.mock(TransportConnectionWriter.class);
|
context.mock(TransportConnectionWriter.class);
|
||||||
|
|
||||||
@@ -76,8 +83,8 @@ public class PollerTest extends BrambleMockTestCase {
|
|||||||
TransportId duplexId = getTransportId();
|
TransportId duplexId = getTransportId();
|
||||||
DuplexPlugin duplexPlugin1 =
|
DuplexPlugin duplexPlugin1 =
|
||||||
context.mock(DuplexPlugin.class, "duplexPlugin1");
|
context.mock(DuplexPlugin.class, "duplexPlugin1");
|
||||||
List<DuplexPlugin> duplexPlugins = Arrays.asList(duplexPlugin,
|
List<DuplexPlugin> duplexPlugins =
|
||||||
duplexPlugin1);
|
asList(duplexPlugin, duplexPlugin1);
|
||||||
DuplexTransportConnection duplexConnection =
|
DuplexTransportConnection duplexConnection =
|
||||||
context.mock(DuplexTransportConnection.class);
|
context.mock(DuplexTransportConnection.class);
|
||||||
|
|
||||||
@@ -96,8 +103,12 @@ public class PollerTest extends BrambleMockTestCase {
|
|||||||
will(returnValue(simplexId1));
|
will(returnValue(simplexId1));
|
||||||
oneOf(connectionRegistry).isConnected(contactId, simplexId1);
|
oneOf(connectionRegistry).isConnected(contactId, simplexId1);
|
||||||
will(returnValue(false));
|
will(returnValue(false));
|
||||||
|
// Get the transport properties
|
||||||
|
oneOf(transportPropertyManager).getRemoteProperties(contactId,
|
||||||
|
simplexId1);
|
||||||
|
will(returnValue(properties));
|
||||||
// Connect to the contact
|
// Connect to the contact
|
||||||
oneOf(simplexPlugin1).createWriter(contactId);
|
oneOf(simplexPlugin1).createWriter(properties);
|
||||||
will(returnValue(simplexWriter));
|
will(returnValue(simplexWriter));
|
||||||
// Pass the connection to the connection manager
|
// Pass the connection to the connection manager
|
||||||
oneOf(connectionManager).manageOutgoingConnection(contactId,
|
oneOf(connectionManager).manageOutgoingConnection(contactId,
|
||||||
@@ -105,7 +116,7 @@ public class PollerTest extends BrambleMockTestCase {
|
|||||||
// Get the duplex plugins
|
// Get the duplex plugins
|
||||||
oneOf(pluginManager).getDuplexPlugins();
|
oneOf(pluginManager).getDuplexPlugins();
|
||||||
will(returnValue(duplexPlugins));
|
will(returnValue(duplexPlugins));
|
||||||
// The first plugin supports polling
|
// The duplex plugin supports polling
|
||||||
oneOf(duplexPlugin).shouldPoll();
|
oneOf(duplexPlugin).shouldPoll();
|
||||||
will(returnValue(true));
|
will(returnValue(true));
|
||||||
// Check whether the contact is already connected
|
// Check whether the contact is already connected
|
||||||
@@ -113,8 +124,12 @@ public class PollerTest extends BrambleMockTestCase {
|
|||||||
will(returnValue(duplexId));
|
will(returnValue(duplexId));
|
||||||
oneOf(connectionRegistry).isConnected(contactId, duplexId);
|
oneOf(connectionRegistry).isConnected(contactId, duplexId);
|
||||||
will(returnValue(false));
|
will(returnValue(false));
|
||||||
|
// Get the transport properties
|
||||||
|
oneOf(transportPropertyManager).getRemoteProperties(contactId,
|
||||||
|
duplexId);
|
||||||
|
will(returnValue(properties));
|
||||||
// Connect to the contact
|
// Connect to the contact
|
||||||
oneOf(duplexPlugin).createConnection(contactId);
|
oneOf(duplexPlugin).createConnection(properties);
|
||||||
will(returnValue(duplexConnection));
|
will(returnValue(duplexConnection));
|
||||||
// Pass the connection to the connection manager
|
// Pass the connection to the connection manager
|
||||||
oneOf(connectionManager).manageOutgoingConnection(contactId,
|
oneOf(connectionManager).manageOutgoingConnection(contactId,
|
||||||
@@ -125,7 +140,8 @@ public class PollerTest extends BrambleMockTestCase {
|
|||||||
}});
|
}});
|
||||||
|
|
||||||
Poller p = new Poller(ioExecutor, scheduler, connectionManager,
|
Poller p = new Poller(ioExecutor, scheduler, connectionManager,
|
||||||
connectionRegistry, pluginManager, random, clock);
|
connectionRegistry, pluginManager, transportPropertyManager,
|
||||||
|
random, clock);
|
||||||
|
|
||||||
p.eventOccurred(new ContactStatusChangedEvent(contactId, true));
|
p.eventOccurred(new ContactStatusChangedEvent(contactId, true));
|
||||||
}
|
}
|
||||||
@@ -165,8 +181,12 @@ public class PollerTest extends BrambleMockTestCase {
|
|||||||
// Check whether the contact is already connected
|
// Check whether the contact is already connected
|
||||||
oneOf(connectionRegistry).isConnected(contactId, transportId);
|
oneOf(connectionRegistry).isConnected(contactId, transportId);
|
||||||
will(returnValue(false));
|
will(returnValue(false));
|
||||||
|
// Get the transport properties
|
||||||
|
oneOf(transportPropertyManager).getRemoteProperties(contactId,
|
||||||
|
transportId);
|
||||||
|
will(returnValue(properties));
|
||||||
// Connect to the contact
|
// Connect to the contact
|
||||||
oneOf(plugin).createConnection(contactId);
|
oneOf(plugin).createConnection(properties);
|
||||||
will(returnValue(duplexConnection));
|
will(returnValue(duplexConnection));
|
||||||
// Pass the connection to the connection manager
|
// Pass the connection to the connection manager
|
||||||
oneOf(connectionManager).manageOutgoingConnection(contactId,
|
oneOf(connectionManager).manageOutgoingConnection(contactId,
|
||||||
@@ -174,15 +194,15 @@ public class PollerTest extends BrambleMockTestCase {
|
|||||||
}});
|
}});
|
||||||
|
|
||||||
Poller p = new Poller(ioExecutor, scheduler, connectionManager,
|
Poller p = new Poller(ioExecutor, scheduler, connectionManager,
|
||||||
connectionRegistry, pluginManager, random, clock);
|
connectionRegistry, pluginManager, transportPropertyManager,
|
||||||
|
random, clock);
|
||||||
|
|
||||||
p.eventOccurred(new ConnectionClosedEvent(contactId, transportId,
|
p.eventOccurred(new ConnectionClosedEvent(contactId, transportId,
|
||||||
false));
|
false));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRescheduleOnConnectionOpened() throws Exception {
|
public void testRescheduleOnConnectionOpened() {
|
||||||
Plugin plugin = context.mock(Plugin.class);
|
Plugin plugin = context.mock(Plugin.class);
|
||||||
|
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
@@ -205,14 +225,15 @@ public class PollerTest extends BrambleMockTestCase {
|
|||||||
}});
|
}});
|
||||||
|
|
||||||
Poller p = new Poller(ioExecutor, scheduler, connectionManager,
|
Poller p = new Poller(ioExecutor, scheduler, connectionManager,
|
||||||
connectionRegistry, pluginManager, random, clock);
|
connectionRegistry, pluginManager, transportPropertyManager,
|
||||||
|
random, clock);
|
||||||
|
|
||||||
p.eventOccurred(new ConnectionOpenedEvent(contactId, transportId,
|
p.eventOccurred(new ConnectionOpenedEvent(contactId, transportId,
|
||||||
false));
|
false));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRescheduleDoesNotReplaceEarlierTask() throws Exception {
|
public void testRescheduleDoesNotReplaceEarlierTask() {
|
||||||
Plugin plugin = context.mock(Plugin.class);
|
Plugin plugin = context.mock(Plugin.class);
|
||||||
|
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
@@ -248,7 +269,8 @@ public class PollerTest extends BrambleMockTestCase {
|
|||||||
}});
|
}});
|
||||||
|
|
||||||
Poller p = new Poller(ioExecutor, scheduler, connectionManager,
|
Poller p = new Poller(ioExecutor, scheduler, connectionManager,
|
||||||
connectionRegistry, pluginManager, random, clock);
|
connectionRegistry, pluginManager, transportPropertyManager,
|
||||||
|
random, clock);
|
||||||
|
|
||||||
p.eventOccurred(new ConnectionOpenedEvent(contactId, transportId,
|
p.eventOccurred(new ConnectionOpenedEvent(contactId, transportId,
|
||||||
false));
|
false));
|
||||||
@@ -257,7 +279,7 @@ public class PollerTest extends BrambleMockTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRescheduleReplacesLaterTask() throws Exception {
|
public void testRescheduleReplacesLaterTask() {
|
||||||
Plugin plugin = context.mock(Plugin.class);
|
Plugin plugin = context.mock(Plugin.class);
|
||||||
|
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
@@ -296,7 +318,8 @@ public class PollerTest extends BrambleMockTestCase {
|
|||||||
}});
|
}});
|
||||||
|
|
||||||
Poller p = new Poller(ioExecutor, scheduler, connectionManager,
|
Poller p = new Poller(ioExecutor, scheduler, connectionManager,
|
||||||
connectionRegistry, pluginManager, random, clock);
|
connectionRegistry, pluginManager, transportPropertyManager,
|
||||||
|
random, clock);
|
||||||
|
|
||||||
p.eventOccurred(new ConnectionOpenedEvent(contactId, transportId,
|
p.eventOccurred(new ConnectionOpenedEvent(contactId, transportId,
|
||||||
false));
|
false));
|
||||||
@@ -306,8 +329,7 @@ public class PollerTest extends BrambleMockTestCase {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testPollsOnTransportEnabled() throws Exception {
|
public void testPollsOnTransportEnabled() throws Exception {
|
||||||
Plugin plugin = context.mock(Plugin.class);
|
DuplexPlugin plugin = context.mock(DuplexPlugin.class);
|
||||||
List<ContactId> connected = Collections.singletonList(contactId);
|
|
||||||
|
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
allowing(plugin).getId();
|
allowing(plugin).getId();
|
||||||
@@ -335,20 +357,69 @@ public class PollerTest extends BrambleMockTestCase {
|
|||||||
oneOf(scheduler).schedule(with(any(Runnable.class)),
|
oneOf(scheduler).schedule(with(any(Runnable.class)),
|
||||||
with((long) (pollingInterval * 0.5)), with(MILLISECONDS));
|
with((long) (pollingInterval * 0.5)), with(MILLISECONDS));
|
||||||
will(returnValue(future));
|
will(returnValue(future));
|
||||||
// Poll the plugin
|
// Get the transport properties and connected contacts
|
||||||
|
oneOf(transportPropertyManager).getRemoteProperties(transportId);
|
||||||
|
will(returnValue(singletonMap(contactId, properties)));
|
||||||
oneOf(connectionRegistry).getConnectedContacts(transportId);
|
oneOf(connectionRegistry).getConnectedContacts(transportId);
|
||||||
will(returnValue(connected));
|
will(returnValue(emptyList()));
|
||||||
oneOf(plugin).poll(connected);
|
// Poll the plugin
|
||||||
|
oneOf(plugin).poll(singletonMap(contactId, properties));
|
||||||
}});
|
}});
|
||||||
|
|
||||||
Poller p = new Poller(ioExecutor, scheduler, connectionManager,
|
Poller p = new Poller(ioExecutor, scheduler, connectionManager,
|
||||||
connectionRegistry, pluginManager, random, clock);
|
connectionRegistry, pluginManager, transportPropertyManager,
|
||||||
|
random, clock);
|
||||||
|
|
||||||
p.eventOccurred(new TransportEnabledEvent(transportId));
|
p.eventOccurred(new TransportEnabledEvent(transportId));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCancelsPollingOnTransportDisabled() throws Exception {
|
public void testDoesNotPollIfAllContactsAreConnected() throws Exception {
|
||||||
|
DuplexPlugin plugin = context.mock(DuplexPlugin.class);
|
||||||
|
|
||||||
|
context.checking(new Expectations() {{
|
||||||
|
allowing(plugin).getId();
|
||||||
|
will(returnValue(transportId));
|
||||||
|
// Get the plugin
|
||||||
|
oneOf(pluginManager).getPlugin(transportId);
|
||||||
|
will(returnValue(plugin));
|
||||||
|
// The plugin supports polling
|
||||||
|
oneOf(plugin).shouldPoll();
|
||||||
|
will(returnValue(true));
|
||||||
|
// Schedule a polling task immediately
|
||||||
|
oneOf(clock).currentTimeMillis();
|
||||||
|
will(returnValue(now));
|
||||||
|
oneOf(scheduler).schedule(with(any(Runnable.class)), with(0L),
|
||||||
|
with(MILLISECONDS));
|
||||||
|
will(returnValue(future));
|
||||||
|
will(new RunAction());
|
||||||
|
// Running the polling task schedules the next polling task
|
||||||
|
oneOf(plugin).getPollingInterval();
|
||||||
|
will(returnValue(pollingInterval));
|
||||||
|
oneOf(random).nextDouble();
|
||||||
|
will(returnValue(0.5));
|
||||||
|
oneOf(clock).currentTimeMillis();
|
||||||
|
will(returnValue(now));
|
||||||
|
oneOf(scheduler).schedule(with(any(Runnable.class)),
|
||||||
|
with((long) (pollingInterval * 0.5)), with(MILLISECONDS));
|
||||||
|
will(returnValue(future));
|
||||||
|
// Get the transport properties and connected contacts
|
||||||
|
oneOf(transportPropertyManager).getRemoteProperties(transportId);
|
||||||
|
will(returnValue(singletonMap(contactId, properties)));
|
||||||
|
oneOf(connectionRegistry).getConnectedContacts(transportId);
|
||||||
|
will(returnValue(singletonList(contactId)));
|
||||||
|
// All contacts are connected, so don't poll the plugin
|
||||||
|
}});
|
||||||
|
|
||||||
|
Poller p = new Poller(ioExecutor, scheduler, connectionManager,
|
||||||
|
connectionRegistry, pluginManager, transportPropertyManager,
|
||||||
|
random, clock);
|
||||||
|
|
||||||
|
p.eventOccurred(new TransportEnabledEvent(transportId));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCancelsPollingOnTransportDisabled() {
|
||||||
Plugin plugin = context.mock(Plugin.class);
|
Plugin plugin = context.mock(Plugin.class);
|
||||||
|
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
@@ -371,7 +442,8 @@ public class PollerTest extends BrambleMockTestCase {
|
|||||||
}});
|
}});
|
||||||
|
|
||||||
Poller p = new Poller(ioExecutor, scheduler, connectionManager,
|
Poller p = new Poller(ioExecutor, scheduler, connectionManager,
|
||||||
connectionRegistry, pluginManager, random, clock);
|
connectionRegistry, pluginManager, transportPropertyManager,
|
||||||
|
random, clock);
|
||||||
|
|
||||||
p.eventOccurred(new TransportEnabledEvent(transportId));
|
p.eventOccurred(new TransportEnabledEvent(transportId));
|
||||||
p.eventOccurred(new TransportDisabledEvent(transportId));
|
p.eventOccurred(new TransportDisabledEvent(transportId));
|
||||||
|
|||||||
@@ -23,8 +23,6 @@ import java.net.ServerSocket;
|
|||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.Hashtable;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.concurrent.CountDownLatch;
|
import java.util.concurrent.CountDownLatch;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
@@ -40,7 +38,6 @@ import static org.junit.Assert.assertTrue;
|
|||||||
|
|
||||||
public class LanTcpPluginTest extends BrambleTestCase {
|
public class LanTcpPluginTest extends BrambleTestCase {
|
||||||
|
|
||||||
private final ContactId contactId = new ContactId(234);
|
|
||||||
private final Backoff backoff = new TestBackoff();
|
private final Backoff backoff = new TestBackoff();
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -160,12 +157,10 @@ public class LanTcpPluginTest extends BrambleTestCase {
|
|||||||
error.set(true);
|
error.set(true);
|
||||||
}
|
}
|
||||||
}).start();
|
}).start();
|
||||||
// Tell the plugin about the port
|
// Connect to the port
|
||||||
TransportProperties p = new TransportProperties();
|
TransportProperties p = new TransportProperties();
|
||||||
p.put("ipPorts", addrString + ":" + port);
|
p.put("ipPorts", addrString + ":" + port);
|
||||||
callback.remote.put(contactId, p);
|
DuplexTransportConnection d = plugin.createConnection(p);
|
||||||
// Connect to the port
|
|
||||||
DuplexTransportConnection d = plugin.createConnection(contactId);
|
|
||||||
assertNotNull(d);
|
assertNotNull(d);
|
||||||
// Check that the connection was accepted
|
// Check that the connection was accepted
|
||||||
assertTrue(latch.await(5, SECONDS));
|
assertTrue(latch.await(5, SECONDS));
|
||||||
@@ -281,7 +276,7 @@ public class LanTcpPluginTest extends BrambleTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testComparatorPrefersNonZeroPorts() throws Exception {
|
public void testComparatorPrefersNonZeroPorts() {
|
||||||
Comparator<InetSocketAddress> comparator = new LanAddressComparator();
|
Comparator<InetSocketAddress> comparator = new LanAddressComparator();
|
||||||
InetSocketAddress nonZero = new InetSocketAddress("1.2.3.4", 1234);
|
InetSocketAddress nonZero = new InetSocketAddress("1.2.3.4", 1234);
|
||||||
InetSocketAddress zero = new InetSocketAddress("1.2.3.4", 0);
|
InetSocketAddress zero = new InetSocketAddress("1.2.3.4", 0);
|
||||||
@@ -294,7 +289,7 @@ public class LanTcpPluginTest extends BrambleTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testComparatorPrefersLongerPrefixes() throws Exception {
|
public void testComparatorPrefersLongerPrefixes() {
|
||||||
Comparator<InetSocketAddress> comparator = new LanAddressComparator();
|
Comparator<InetSocketAddress> comparator = new LanAddressComparator();
|
||||||
InetSocketAddress prefix192 = new InetSocketAddress("192.168.0.1", 0);
|
InetSocketAddress prefix192 = new InetSocketAddress("192.168.0.1", 0);
|
||||||
InetSocketAddress prefix172 = new InetSocketAddress("172.16.0.1", 0);
|
InetSocketAddress prefix172 = new InetSocketAddress("172.16.0.1", 0);
|
||||||
@@ -314,7 +309,7 @@ public class LanTcpPluginTest extends BrambleTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testComparatorPrefersSiteLocalToLinkLocal() throws Exception {
|
public void testComparatorPrefersSiteLocalToLinkLocal() {
|
||||||
Comparator<InetSocketAddress> comparator = new LanAddressComparator();
|
Comparator<InetSocketAddress> comparator = new LanAddressComparator();
|
||||||
InetSocketAddress prefix192 = new InetSocketAddress("192.168.0.1", 0);
|
InetSocketAddress prefix192 = new InetSocketAddress("192.168.0.1", 0);
|
||||||
InetSocketAddress prefix172 = new InetSocketAddress("172.16.0.1", 0);
|
InetSocketAddress prefix172 = new InetSocketAddress("172.16.0.1", 0);
|
||||||
@@ -345,8 +340,6 @@ public class LanTcpPluginTest extends BrambleTestCase {
|
|||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
private static class Callback implements DuplexPluginCallback {
|
private static class Callback implements DuplexPluginCallback {
|
||||||
|
|
||||||
private final Map<ContactId, TransportProperties> remote =
|
|
||||||
new Hashtable<>();
|
|
||||||
private final CountDownLatch propertiesLatch = new CountDownLatch(1);
|
private final CountDownLatch propertiesLatch = new CountDownLatch(1);
|
||||||
private final CountDownLatch connectionsLatch = new CountDownLatch(1);
|
private final CountDownLatch connectionsLatch = new CountDownLatch(1);
|
||||||
private final TransportProperties local = new TransportProperties();
|
private final TransportProperties local = new TransportProperties();
|
||||||
@@ -361,16 +354,6 @@ public class LanTcpPluginTest extends BrambleTestCase {
|
|||||||
return local;
|
return local;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public Map<ContactId, TransportProperties> getRemoteProperties() {
|
|
||||||
return remote;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public TransportProperties getRemoteProperties(ContactId c) {
|
|
||||||
return remote.get(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void mergeSettings(Settings s) {
|
public void mergeSettings(Settings s) {
|
||||||
}
|
}
|
||||||
@@ -381,20 +364,6 @@ public class LanTcpPluginTest extends BrambleTestCase {
|
|||||||
propertiesLatch.countDown();
|
propertiesLatch.countDown();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public int showChoice(String[] options, String... message) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean showConfirmationMessage(String... message) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void showMessage(String... message) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void incomingConnectionCreated(DuplexTransportConnection d) {
|
public void incomingConnectionCreated(DuplexTransportConnection d) {
|
||||||
connectionsLatch.countDown();
|
connectionsLatch.countDown();
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ public class CaptureArgumentAction<T> implements Action {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object invoke(Invocation invocation) throws Throwable {
|
public Object invoke(Invocation invocation) {
|
||||||
captured.set(capturedClass.cast(invocation.getParameter(index)));
|
captured.set(capturedClass.cast(invocation.getParameter(index)));
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,25 +9,31 @@ import java.io.File;
|
|||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
public class TestDatabaseConfig implements DatabaseConfig {
|
public class TestDatabaseConfig implements DatabaseConfig {
|
||||||
|
|
||||||
private final File dir;
|
private final File dbDir, keyDir;
|
||||||
private final long maxSize;
|
private final long maxSize;
|
||||||
private volatile SecretKey key = new SecretKey(new byte[SecretKey.LENGTH]);
|
private volatile SecretKey key = new SecretKey(new byte[SecretKey.LENGTH]);
|
||||||
|
|
||||||
public TestDatabaseConfig(File dir, long maxSize) {
|
public TestDatabaseConfig(File testDir, long maxSize) {
|
||||||
this.dir = dir;
|
dbDir = new File(testDir, "db");
|
||||||
|
keyDir = new File(testDir, "key");
|
||||||
this.maxSize = maxSize;
|
this.maxSize = maxSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean databaseExists() {
|
public boolean databaseExists() {
|
||||||
if (!dir.isDirectory()) return false;
|
if (!dbDir.isDirectory()) return false;
|
||||||
File[] files = dir.listFiles();
|
File[] files = dbDir.listFiles();
|
||||||
return files != null && files.length > 0;
|
return files != null && files.length > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public File getDatabaseDirectory() {
|
public File getDatabaseDirectory() {
|
||||||
return dir;
|
return dbDir;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public File getDatabaseKeyDirectory() {
|
||||||
|
return keyDir;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -9,13 +9,14 @@ import org.briarproject.bramble.api.plugin.simplex.SimplexPluginCallback;
|
|||||||
import org.briarproject.bramble.api.plugin.simplex.SimplexPluginFactory;
|
import org.briarproject.bramble.api.plugin.simplex.SimplexPluginFactory;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
import dagger.Module;
|
import dagger.Module;
|
||||||
import dagger.Provides;
|
import dagger.Provides;
|
||||||
|
|
||||||
|
import static java.util.Collections.emptyList;
|
||||||
|
import static java.util.Collections.singletonList;
|
||||||
import static org.briarproject.bramble.test.TestUtils.getTransportId;
|
import static org.briarproject.bramble.test.TestUtils.getTransportId;
|
||||||
|
|
||||||
@Module
|
@Module
|
||||||
@@ -51,12 +52,17 @@ public class TestPluginConfigModule {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Collection<DuplexPluginFactory> getDuplexFactories() {
|
public Collection<DuplexPluginFactory> getDuplexFactories() {
|
||||||
return Collections.emptyList();
|
return emptyList();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Collection<SimplexPluginFactory> getSimplexFactories() {
|
public Collection<SimplexPluginFactory> getSimplexFactories() {
|
||||||
return Collections.singletonList(simplex);
|
return singletonList(simplex);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean shouldPoll() {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
return pluginConfig;
|
return pluginConfig;
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import org.junit.Test;
|
|||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
|
|
||||||
import static java.util.Collections.singletonList;
|
import static java.util.Collections.singletonList;
|
||||||
@@ -54,6 +55,7 @@ public class KeyManagerImplTest extends BrambleMockTestCase {
|
|||||||
new StreamContext(contactId, transportId, getSecretKey(),
|
new StreamContext(contactId, transportId, getSecretKey(),
|
||||||
getSecretKey(), 1);
|
getSecretKey(), 1);
|
||||||
private final byte[] tag = getRandomBytes(TAG_LENGTH);
|
private final byte[] tag = getRandomBytes(TAG_LENGTH);
|
||||||
|
private final Random random = new Random();
|
||||||
|
|
||||||
private final KeyManagerImpl keyManager = new KeyManagerImpl(db, executor,
|
private final KeyManagerImpl keyManager = new KeyManagerImpl(db, executor,
|
||||||
pluginConfig, transportKeyManagerFactory);
|
pluginConfig, transportKeyManagerFactory);
|
||||||
@@ -102,30 +104,18 @@ public class KeyManagerImplTest extends BrambleMockTestCase {
|
|||||||
public void testAddContact() throws Exception {
|
public void testAddContact() throws Exception {
|
||||||
SecretKey secretKey = getSecretKey();
|
SecretKey secretKey = getSecretKey();
|
||||||
long timestamp = System.currentTimeMillis();
|
long timestamp = System.currentTimeMillis();
|
||||||
boolean alice = new Random().nextBoolean();
|
boolean alice = random.nextBoolean();
|
||||||
|
boolean active = random.nextBoolean();
|
||||||
|
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
oneOf(transportKeyManager).addContact(txn, contactId, secretKey,
|
oneOf(transportKeyManager).addContact(txn, contactId, secretKey,
|
||||||
timestamp, alice);
|
timestamp, alice, active);
|
||||||
}});
|
|
||||||
|
|
||||||
keyManager.addContact(txn, contactId, secretKey, timestamp, alice);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testAddUnboundKeys() throws Exception {
|
|
||||||
SecretKey secretKey = getSecretKey();
|
|
||||||
long timestamp = System.currentTimeMillis();
|
|
||||||
boolean alice = new Random().nextBoolean();
|
|
||||||
|
|
||||||
context.checking(new Expectations() {{
|
|
||||||
oneOf(transportKeyManager).addUnboundKeys(txn, secretKey,
|
|
||||||
timestamp, alice);
|
|
||||||
will(returnValue(keySetId));
|
will(returnValue(keySetId));
|
||||||
}});
|
}});
|
||||||
|
|
||||||
assertEquals(singletonMap(transportId, keySetId),
|
Map<TransportId, KeySetId> ids = keyManager.addContact(txn, contactId,
|
||||||
keyManager.addUnboundKeys(txn, secretKey, timestamp, alice));
|
secretKey, timestamp, alice, active);
|
||||||
|
assertEquals(singletonMap(transportId, keySetId), ids);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
@@ -61,7 +61,6 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase {
|
|||||||
private final ContactId contactId1 = new ContactId(234);
|
private final ContactId contactId1 = new ContactId(234);
|
||||||
private final KeySetId keySetId = new KeySetId(345);
|
private final KeySetId keySetId = new KeySetId(345);
|
||||||
private final KeySetId keySetId1 = new KeySetId(456);
|
private final KeySetId keySetId1 = new KeySetId(456);
|
||||||
private final KeySetId keySetId2 = new KeySetId(567);
|
|
||||||
private final SecretKey tagKey = TestUtils.getSecretKey();
|
private final SecretKey tagKey = TestUtils.getSecretKey();
|
||||||
private final SecretKey headerKey = TestUtils.getSecretKey();
|
private final SecretKey headerKey = TestUtils.getSecretKey();
|
||||||
private final SecretKey masterKey = TestUtils.getSecretKey();
|
private final SecretKey masterKey = TestUtils.getSecretKey();
|
||||||
@@ -71,14 +70,11 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase {
|
|||||||
public void testKeysAreRotatedAtStartup() throws Exception {
|
public void testKeysAreRotatedAtStartup() throws Exception {
|
||||||
TransportKeys shouldRotate = createTransportKeys(900, 0, true);
|
TransportKeys shouldRotate = createTransportKeys(900, 0, true);
|
||||||
TransportKeys shouldNotRotate = createTransportKeys(1000, 0, true);
|
TransportKeys shouldNotRotate = createTransportKeys(1000, 0, true);
|
||||||
TransportKeys shouldRotate1 = createTransportKeys(999, 0, false);
|
|
||||||
Collection<KeySet> loaded = asList(
|
Collection<KeySet> loaded = asList(
|
||||||
new KeySet(keySetId, contactId, shouldRotate),
|
new KeySet(keySetId, contactId, shouldRotate),
|
||||||
new KeySet(keySetId1, contactId1, shouldNotRotate),
|
new KeySet(keySetId1, contactId1, shouldNotRotate)
|
||||||
new KeySet(keySetId2, null, shouldRotate1)
|
|
||||||
);
|
);
|
||||||
TransportKeys rotated = createTransportKeys(1000, 0, true);
|
TransportKeys rotated = createTransportKeys(1000, 0, true);
|
||||||
TransportKeys rotated1 = createTransportKeys(1000, 0, false);
|
|
||||||
Transaction txn = new Transaction(null, false);
|
Transaction txn = new Transaction(null, false);
|
||||||
|
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
@@ -93,8 +89,6 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase {
|
|||||||
will(returnValue(rotated));
|
will(returnValue(rotated));
|
||||||
oneOf(transportCrypto).rotateTransportKeys(shouldNotRotate, 1000);
|
oneOf(transportCrypto).rotateTransportKeys(shouldNotRotate, 1000);
|
||||||
will(returnValue(shouldNotRotate));
|
will(returnValue(shouldNotRotate));
|
||||||
oneOf(transportCrypto).rotateTransportKeys(shouldRotate1, 1000);
|
|
||||||
will(returnValue(rotated1));
|
|
||||||
// Encode the tags (3 sets per contact)
|
// Encode the tags (3 sets per contact)
|
||||||
for (long i = 0; i < REORDERING_WINDOW_SIZE; i++) {
|
for (long i = 0; i < REORDERING_WINDOW_SIZE; i++) {
|
||||||
exactly(6).of(transportCrypto).encodeTag(
|
exactly(6).of(transportCrypto).encodeTag(
|
||||||
@@ -103,10 +97,8 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase {
|
|||||||
will(new EncodeTagAction());
|
will(new EncodeTagAction());
|
||||||
}
|
}
|
||||||
// Save the keys that were rotated
|
// Save the keys that were rotated
|
||||||
oneOf(db).updateTransportKeys(txn, asList(
|
oneOf(db).updateTransportKeys(txn,
|
||||||
new KeySet(keySetId, contactId, rotated),
|
singletonList(new KeySet(keySetId, contactId, rotated)));
|
||||||
new KeySet(keySetId2, null, rotated1))
|
|
||||||
);
|
|
||||||
// Schedule key rotation at the start of the next rotation period
|
// Schedule key rotation at the start of the next rotation period
|
||||||
oneOf(scheduler).schedule(with(any(Runnable.class)),
|
oneOf(scheduler).schedule(with(any(Runnable.class)),
|
||||||
with(rotationPeriodLength - 1), with(MILLISECONDS));
|
with(rotationPeriodLength - 1), with(MILLISECONDS));
|
||||||
@@ -153,43 +145,11 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase {
|
|||||||
maxLatency);
|
maxLatency);
|
||||||
// The timestamp is 1 ms before the start of rotation period 1000
|
// The timestamp is 1 ms before the start of rotation period 1000
|
||||||
long timestamp = rotationPeriodLength * 1000 - 1;
|
long timestamp = rotationPeriodLength * 1000 - 1;
|
||||||
transportKeyManager.addContact(txn, contactId, masterKey, timestamp,
|
assertEquals(keySetId, transportKeyManager.addContact(txn, contactId,
|
||||||
alice);
|
masterKey, timestamp, alice, true));
|
||||||
assertTrue(transportKeyManager.canSendOutgoingStreams(contactId));
|
assertTrue(transportKeyManager.canSendOutgoingStreams(contactId));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testKeysAreRotatedWhenAddingUnboundKeys() throws Exception {
|
|
||||||
boolean alice = random.nextBoolean();
|
|
||||||
TransportKeys transportKeys = createTransportKeys(999, 0, false);
|
|
||||||
TransportKeys rotated = createTransportKeys(1000, 0, false);
|
|
||||||
Transaction txn = new Transaction(null, false);
|
|
||||||
|
|
||||||
context.checking(new Expectations() {{
|
|
||||||
oneOf(transportCrypto).deriveTransportKeys(transportId, masterKey,
|
|
||||||
999, alice, false);
|
|
||||||
will(returnValue(transportKeys));
|
|
||||||
// Get the current time (1 ms after start of rotation period 1000)
|
|
||||||
oneOf(clock).currentTimeMillis();
|
|
||||||
will(returnValue(rotationPeriodLength * 1000 + 1));
|
|
||||||
// Rotate the transport keys
|
|
||||||
oneOf(transportCrypto).rotateTransportKeys(transportKeys, 1000);
|
|
||||||
will(returnValue(rotated));
|
|
||||||
// Save the keys
|
|
||||||
oneOf(db).addTransportKeys(txn, null, rotated);
|
|
||||||
will(returnValue(keySetId));
|
|
||||||
}});
|
|
||||||
|
|
||||||
TransportKeyManager transportKeyManager = new TransportKeyManagerImpl(
|
|
||||||
db, transportCrypto, dbExecutor, scheduler, clock, transportId,
|
|
||||||
maxLatency);
|
|
||||||
// The timestamp is 1 ms before the start of rotation period 1000
|
|
||||||
long timestamp = rotationPeriodLength * 1000 - 1;
|
|
||||||
assertEquals(keySetId, transportKeyManager.addUnboundKeys(txn,
|
|
||||||
masterKey, timestamp, alice));
|
|
||||||
assertFalse(transportKeyManager.canSendOutgoingStreams(contactId));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testOutgoingStreamContextIsNullIfContactIsNotFound()
|
public void testOutgoingStreamContextIsNullIfContactIsNotFound()
|
||||||
throws Exception {
|
throws Exception {
|
||||||
@@ -211,15 +171,15 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase {
|
|||||||
MAX_32_BIT_UNSIGNED + 1, true);
|
MAX_32_BIT_UNSIGNED + 1, true);
|
||||||
Transaction txn = new Transaction(null, false);
|
Transaction txn = new Transaction(null, false);
|
||||||
|
|
||||||
expectAddContactNoRotation(alice, transportKeys, txn);
|
expectAddContactNoRotation(alice, true, transportKeys, txn);
|
||||||
|
|
||||||
TransportKeyManager transportKeyManager = new TransportKeyManagerImpl(
|
TransportKeyManager transportKeyManager = new TransportKeyManagerImpl(
|
||||||
db, transportCrypto, dbExecutor, scheduler, clock, transportId,
|
db, transportCrypto, dbExecutor, scheduler, clock, transportId,
|
||||||
maxLatency);
|
maxLatency);
|
||||||
// The timestamp is at the start of rotation period 1000
|
// The timestamp is at the start of rotation period 1000
|
||||||
long timestamp = rotationPeriodLength * 1000;
|
long timestamp = rotationPeriodLength * 1000;
|
||||||
transportKeyManager.addContact(txn, contactId, masterKey, timestamp,
|
assertEquals(keySetId, transportKeyManager.addContact(txn, contactId,
|
||||||
alice);
|
masterKey, timestamp, alice, true));
|
||||||
assertFalse(transportKeyManager.canSendOutgoingStreams(contactId));
|
assertFalse(transportKeyManager.canSendOutgoingStreams(contactId));
|
||||||
assertNull(transportKeyManager.getStreamContext(txn, contactId));
|
assertNull(transportKeyManager.getStreamContext(txn, contactId));
|
||||||
}
|
}
|
||||||
@@ -232,7 +192,7 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase {
|
|||||||
MAX_32_BIT_UNSIGNED, true);
|
MAX_32_BIT_UNSIGNED, true);
|
||||||
Transaction txn = new Transaction(null, false);
|
Transaction txn = new Transaction(null, false);
|
||||||
|
|
||||||
expectAddContactNoRotation(alice, transportKeys, txn);
|
expectAddContactNoRotation(alice, true, transportKeys, txn);
|
||||||
|
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
// Increment the stream counter
|
// Increment the stream counter
|
||||||
@@ -244,8 +204,8 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase {
|
|||||||
maxLatency);
|
maxLatency);
|
||||||
// The timestamp is at the start of rotation period 1000
|
// The timestamp is at the start of rotation period 1000
|
||||||
long timestamp = rotationPeriodLength * 1000;
|
long timestamp = rotationPeriodLength * 1000;
|
||||||
transportKeyManager.addContact(txn, contactId, masterKey, timestamp,
|
assertEquals(keySetId, transportKeyManager.addContact(txn, contactId,
|
||||||
alice);
|
masterKey, timestamp, alice, true));
|
||||||
// The first request should return a stream context
|
// The first request should return a stream context
|
||||||
assertTrue(transportKeyManager.canSendOutgoingStreams(contactId));
|
assertTrue(transportKeyManager.canSendOutgoingStreams(contactId));
|
||||||
StreamContext ctx = transportKeyManager.getStreamContext(txn,
|
StreamContext ctx = transportKeyManager.getStreamContext(txn,
|
||||||
@@ -265,19 +225,21 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase {
|
|||||||
public void testIncomingStreamContextIsNullIfTagIsNotFound()
|
public void testIncomingStreamContextIsNullIfTagIsNotFound()
|
||||||
throws Exception {
|
throws Exception {
|
||||||
boolean alice = random.nextBoolean();
|
boolean alice = random.nextBoolean();
|
||||||
TransportKeys transportKeys = createTransportKeys(1000, 0, true);
|
boolean active = random.nextBoolean();
|
||||||
|
TransportKeys transportKeys = createTransportKeys(1000, 0, active);
|
||||||
Transaction txn = new Transaction(null, false);
|
Transaction txn = new Transaction(null, false);
|
||||||
|
|
||||||
expectAddContactNoRotation(alice, transportKeys, txn);
|
expectAddContactNoRotation(alice, active, transportKeys, txn);
|
||||||
|
|
||||||
TransportKeyManager transportKeyManager = new TransportKeyManagerImpl(
|
TransportKeyManager transportKeyManager = new TransportKeyManagerImpl(
|
||||||
db, transportCrypto, dbExecutor, scheduler, clock, transportId,
|
db, transportCrypto, dbExecutor, scheduler, clock, transportId,
|
||||||
maxLatency);
|
maxLatency);
|
||||||
// The timestamp is at the start of rotation period 1000
|
// The timestamp is at the start of rotation period 1000
|
||||||
long timestamp = rotationPeriodLength * 1000;
|
long timestamp = rotationPeriodLength * 1000;
|
||||||
transportKeyManager.addContact(txn, contactId, masterKey, timestamp,
|
assertEquals(keySetId, transportKeyManager.addContact(txn, contactId,
|
||||||
alice);
|
masterKey, timestamp, alice, active));
|
||||||
assertTrue(transportKeyManager.canSendOutgoingStreams(contactId));
|
assertEquals(active,
|
||||||
|
transportKeyManager.canSendOutgoingStreams(contactId));
|
||||||
// The tag should not be recognised
|
// The tag should not be recognised
|
||||||
assertNull(transportKeyManager.getStreamContext(txn,
|
assertNull(transportKeyManager.getStreamContext(txn,
|
||||||
new byte[TAG_LENGTH]));
|
new byte[TAG_LENGTH]));
|
||||||
@@ -327,8 +289,8 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase {
|
|||||||
maxLatency);
|
maxLatency);
|
||||||
// The timestamp is at the start of rotation period 1000
|
// The timestamp is at the start of rotation period 1000
|
||||||
long timestamp = rotationPeriodLength * 1000;
|
long timestamp = rotationPeriodLength * 1000;
|
||||||
transportKeyManager.addContact(txn, contactId, masterKey, timestamp,
|
assertEquals(keySetId, transportKeyManager.addContact(txn, contactId,
|
||||||
alice);
|
masterKey, timestamp, alice, true));
|
||||||
assertTrue(transportKeyManager.canSendOutgoingStreams(contactId));
|
assertTrue(transportKeyManager.canSendOutgoingStreams(contactId));
|
||||||
// Use the first tag (previous rotation period, stream number 0)
|
// Use the first tag (previous rotation period, stream number 0)
|
||||||
assertEquals(REORDERING_WINDOW_SIZE * 3, tags.size());
|
assertEquals(REORDERING_WINDOW_SIZE * 3, tags.size());
|
||||||
@@ -415,23 +377,14 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testBindingAndActivatingKeys() throws Exception {
|
public void testActivatingKeys() throws Exception {
|
||||||
boolean alice = random.nextBoolean();
|
boolean alice = random.nextBoolean();
|
||||||
TransportKeys transportKeys = createTransportKeys(1000, 0, false);
|
TransportKeys transportKeys = createTransportKeys(1000, 0, false);
|
||||||
Transaction txn = new Transaction(null, false);
|
Transaction txn = new Transaction(null, false);
|
||||||
|
|
||||||
expectAddUnboundKeysNoRotation(alice, transportKeys, txn);
|
expectAddContactNoRotation(alice, false, transportKeys, txn);
|
||||||
|
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
// When the keys are bound, encode the tags (3 sets)
|
|
||||||
for (long i = 0; i < REORDERING_WINDOW_SIZE; i++) {
|
|
||||||
exactly(3).of(transportCrypto).encodeTag(
|
|
||||||
with(any(byte[].class)), with(tagKey),
|
|
||||||
with(PROTOCOL_VERSION), with(i));
|
|
||||||
will(new EncodeTagAction());
|
|
||||||
}
|
|
||||||
// Save the key binding
|
|
||||||
oneOf(db).bindTransportKeys(txn, contactId, transportId, keySetId);
|
|
||||||
// Activate the keys
|
// Activate the keys
|
||||||
oneOf(db).setTransportKeysActive(txn, transportId, keySetId);
|
oneOf(db).setTransportKeysActive(txn, transportId, keySetId);
|
||||||
// Increment the stream counter
|
// Increment the stream counter
|
||||||
@@ -443,12 +396,8 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase {
|
|||||||
maxLatency);
|
maxLatency);
|
||||||
// The timestamp is at the start of rotation period 1000
|
// The timestamp is at the start of rotation period 1000
|
||||||
long timestamp = rotationPeriodLength * 1000;
|
long timestamp = rotationPeriodLength * 1000;
|
||||||
assertEquals(keySetId, transportKeyManager.addUnboundKeys(txn,
|
assertEquals(keySetId, transportKeyManager.addContact(txn, contactId,
|
||||||
masterKey, timestamp, alice));
|
masterKey, timestamp, alice, false));
|
||||||
// The keys are unbound so no stream context should be returned
|
|
||||||
assertFalse(transportKeyManager.canSendOutgoingStreams(contactId));
|
|
||||||
assertNull(transportKeyManager.getStreamContext(txn, contactId));
|
|
||||||
transportKeyManager.bindKeys(txn, contactId, keySetId);
|
|
||||||
// The keys are inactive so no stream context should be returned
|
// The keys are inactive so no stream context should be returned
|
||||||
assertFalse(transportKeyManager.canSendOutgoingStreams(contactId));
|
assertFalse(transportKeyManager.canSendOutgoingStreams(contactId));
|
||||||
assertNull(transportKeyManager.getStreamContext(txn, contactId));
|
assertNull(transportKeyManager.getStreamContext(txn, contactId));
|
||||||
@@ -474,18 +423,26 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase {
|
|||||||
// Keep a copy of the tags
|
// Keep a copy of the tags
|
||||||
List<byte[]> tags = new ArrayList<>();
|
List<byte[]> tags = new ArrayList<>();
|
||||||
|
|
||||||
expectAddUnboundKeysNoRotation(alice, transportKeys, txn);
|
|
||||||
|
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
// When the keys are bound, encode the tags (3 sets)
|
oneOf(transportCrypto).deriveTransportKeys(transportId, masterKey,
|
||||||
|
1000, alice, false);
|
||||||
|
will(returnValue(transportKeys));
|
||||||
|
// Get the current time (the start of rotation period 1000)
|
||||||
|
oneOf(clock).currentTimeMillis();
|
||||||
|
will(returnValue(rotationPeriodLength * 1000));
|
||||||
|
// Encode the tags (3 sets)
|
||||||
for (long i = 0; i < REORDERING_WINDOW_SIZE; i++) {
|
for (long i = 0; i < REORDERING_WINDOW_SIZE; i++) {
|
||||||
exactly(3).of(transportCrypto).encodeTag(
|
exactly(3).of(transportCrypto).encodeTag(
|
||||||
with(any(byte[].class)), with(tagKey),
|
with(any(byte[].class)), with(tagKey),
|
||||||
with(PROTOCOL_VERSION), with(i));
|
with(PROTOCOL_VERSION), with(i));
|
||||||
will(new EncodeTagAction(tags));
|
will(new EncodeTagAction(tags));
|
||||||
}
|
}
|
||||||
// Save the key binding
|
// Rotate the transport keys (the keys are unaffected)
|
||||||
oneOf(db).bindTransportKeys(txn, contactId, transportId, keySetId);
|
oneOf(transportCrypto).rotateTransportKeys(transportKeys, 1000);
|
||||||
|
will(returnValue(transportKeys));
|
||||||
|
// Save the keys
|
||||||
|
oneOf(db).addTransportKeys(txn, contactId, transportKeys);
|
||||||
|
will(returnValue(keySetId));
|
||||||
// Encode a new tag after sliding the window
|
// Encode a new tag after sliding the window
|
||||||
oneOf(transportCrypto).encodeTag(with(any(byte[].class)),
|
oneOf(transportCrypto).encodeTag(with(any(byte[].class)),
|
||||||
with(tagKey), with(PROTOCOL_VERSION),
|
with(tagKey), with(PROTOCOL_VERSION),
|
||||||
@@ -505,9 +462,8 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase {
|
|||||||
maxLatency);
|
maxLatency);
|
||||||
// The timestamp is at the start of rotation period 1000
|
// The timestamp is at the start of rotation period 1000
|
||||||
long timestamp = rotationPeriodLength * 1000;
|
long timestamp = rotationPeriodLength * 1000;
|
||||||
assertEquals(keySetId, transportKeyManager.addUnboundKeys(txn,
|
assertEquals(keySetId, transportKeyManager.addContact(txn, contactId,
|
||||||
masterKey, timestamp, alice));
|
masterKey, timestamp, alice, false));
|
||||||
transportKeyManager.bindKeys(txn, contactId, keySetId);
|
|
||||||
// The keys are inactive so no stream context should be returned
|
// The keys are inactive so no stream context should be returned
|
||||||
assertFalse(transportKeyManager.canSendOutgoingStreams(contactId));
|
assertFalse(transportKeyManager.canSendOutgoingStreams(contactId));
|
||||||
assertNull(transportKeyManager.getStreamContext(txn, contactId));
|
assertNull(transportKeyManager.getStreamContext(txn, contactId));
|
||||||
@@ -532,36 +488,11 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase {
|
|||||||
assertEquals(0L, ctx.getStreamNumber());
|
assertEquals(0L, ctx.getStreamNumber());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
private void expectAddContactNoRotation(boolean alice, boolean active,
|
||||||
public void testRemovingUnboundKeys() throws Exception {
|
|
||||||
boolean alice = random.nextBoolean();
|
|
||||||
TransportKeys transportKeys = createTransportKeys(1000, 0, false);
|
|
||||||
Transaction txn = new Transaction(null, false);
|
|
||||||
|
|
||||||
expectAddUnboundKeysNoRotation(alice, transportKeys, txn);
|
|
||||||
|
|
||||||
context.checking(new Expectations() {{
|
|
||||||
// Remove the unbound keys
|
|
||||||
oneOf(db).removeTransportKeys(txn, transportId, keySetId);
|
|
||||||
}});
|
|
||||||
|
|
||||||
TransportKeyManager transportKeyManager = new TransportKeyManagerImpl(
|
|
||||||
db, transportCrypto, dbExecutor, scheduler, clock, transportId,
|
|
||||||
maxLatency);
|
|
||||||
// The timestamp is at the start of rotation period 1000
|
|
||||||
long timestamp = rotationPeriodLength * 1000;
|
|
||||||
assertEquals(keySetId, transportKeyManager.addUnboundKeys(txn,
|
|
||||||
masterKey, timestamp, alice));
|
|
||||||
assertFalse(transportKeyManager.canSendOutgoingStreams(contactId));
|
|
||||||
transportKeyManager.removeKeys(txn, keySetId);
|
|
||||||
assertFalse(transportKeyManager.canSendOutgoingStreams(contactId));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void expectAddContactNoRotation(boolean alice,
|
|
||||||
TransportKeys transportKeys, Transaction txn) throws Exception {
|
TransportKeys transportKeys, Transaction txn) throws Exception {
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
oneOf(transportCrypto).deriveTransportKeys(transportId, masterKey,
|
oneOf(transportCrypto).deriveTransportKeys(transportId, masterKey,
|
||||||
1000, alice, true);
|
1000, alice, active);
|
||||||
will(returnValue(transportKeys));
|
will(returnValue(transportKeys));
|
||||||
// Get the current time (the start of rotation period 1000)
|
// Get the current time (the start of rotation period 1000)
|
||||||
oneOf(clock).currentTimeMillis();
|
oneOf(clock).currentTimeMillis();
|
||||||
@@ -582,24 +513,6 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase {
|
|||||||
}});
|
}});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void expectAddUnboundKeysNoRotation(boolean alice,
|
|
||||||
TransportKeys transportKeys, Transaction txn) throws Exception {
|
|
||||||
context.checking(new Expectations() {{
|
|
||||||
oneOf(transportCrypto).deriveTransportKeys(transportId, masterKey,
|
|
||||||
1000, alice, false);
|
|
||||||
will(returnValue(transportKeys));
|
|
||||||
// Get the current time (the start of rotation period 1000)
|
|
||||||
oneOf(clock).currentTimeMillis();
|
|
||||||
will(returnValue(rotationPeriodLength * 1000));
|
|
||||||
// Rotate the transport keys (the keys are unaffected)
|
|
||||||
oneOf(transportCrypto).rotateTransportKeys(transportKeys, 1000);
|
|
||||||
will(returnValue(transportKeys));
|
|
||||||
// Save the unbound keys
|
|
||||||
oneOf(db).addTransportKeys(txn, null, transportKeys);
|
|
||||||
will(returnValue(keySetId));
|
|
||||||
}});
|
|
||||||
}
|
|
||||||
|
|
||||||
private TransportKeys createTransportKeys(long rotationPeriod,
|
private TransportKeys createTransportKeys(long rotationPeriod,
|
||||||
long streamCounter, boolean active) {
|
long streamCounter, boolean active) {
|
||||||
IncomingKeys inPrev = new IncomingKeys(tagKey, headerKey,
|
IncomingKeys inPrev = new IncomingKeys(tagKey, headerKey,
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user