Compare commits

..

4 Commits

Author SHA1 Message Date
goapunk
a51f0f803f add bt polling speedtest 2018-05-10 14:42:09 +02:00
akwizgran
8f9d7a70bf Pause between connection attempts. 2018-05-08 14:15:39 +01:00
akwizgran
3ea642c6c0 Don't poll again if last poll is still running. 2018-05-08 13:51:39 +01:00
akwizgran
da0a32c613 Poll contacts in series rather than parallel. 2018-05-08 13:51:31 +01:00
422 changed files with 5691 additions and 7449 deletions

View File

@@ -1,27 +1,27 @@
image: briar/ci-image-android:latest image: registry.gitlab.com/fdroid/ci-images-base: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:
before_script:
- set -e
- export GRADLE_USER_HOME=$PWD/.gradle
cache:
paths:
- .gradle/wrapper
- .gradle/caches
script: script:
- ./gradlew --no-daemon animalSnifferMain animalSnifferTest - ./gradlew test
- ./gradlew --no-daemon test
after_script: after_script:
# these file change every time but should not be cached # this file changes 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:
script:
- "curl -X POST -F token=${RELEASE_CHECK_TOKEN} -F ref=master -F variables[RELEASE_TAG]=${CI_COMMIT_REF_NAME} https://code.briarproject.org/api/v4/projects/61/trigger/pipeline"
only:
- tags

View File

@@ -1,5 +1,11 @@
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
@@ -8,11 +14,9 @@ android {
defaultConfig { defaultConfig {
minSdkVersion 14 minSdkVersion 14
targetSdkVersion 26 targetSdkVersion 26
versionCode 10012 versionCode 10001
versionName "1.0.12" versionName "1.0.1"
consumerProguardFiles 'proguard-rules.txt' consumerProguardFiles 'proguard-rules.txt'
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
} }
compileOptions { compileOptions {
@@ -21,54 +25,43 @@ android {
} }
} }
configurations {
tor
}
dependencies { dependencies {
implementation project(path: ':bramble-core', configuration: 'default') implementation project(path: ':bramble-core', configuration: 'default')
implementation 'org.briarproject:jtorctl:0.3' implementation fileTree(dir: 'libs', include: '*.jar')
tor 'org.briarproject:tor-android:0.2.9.16@zip'
annotationProcessor 'com.google.dagger:dagger-compiler:2.0.2' annotationProcessor 'com.google.dagger:dagger-compiler:2.0.2'
compileOnly 'javax.annotation:jsr250-api:1.0' compileOnly 'javax.annotation:jsr250-api:1.0'
androidTestImplementation project(path: ':bramble-api', configuration: 'testOutput')
androidTestImplementation project(path: ':bramble-core', configuration: 'testOutput')
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestAnnotationProcessor 'com.google.dagger:dagger-compiler:2.0.2'
androidTestCompileOnly 'javax.annotation:jsr250-api:1.0'
} }
dependencyVerification { dependencyVerification {
verify = [ verify = [
'com.android.tools.analytics-library:protos:26.1.3:protos-26.1.3.jar:818c9f256f141d9dafec03a1aa2b94d240b2c140acfd7ee31a8b3e6c2b9479e3', 'com.android.tools.analytics-library:protos:26.1.2:protos-26.1.2.jar:52672a0b42b572a06aecc3535d5068eb46c0e15d129b9f1085d3c16a1da5cdbb',
'com.android.tools.analytics-library:shared:26.1.3:shared-26.1.3.jar:7110706c7ada96c8b6f5ca80c478291bc7899d46277de2c48527e045442401a3', 'com.android.tools.analytics-library:shared:26.1.2:shared-26.1.2.jar:5c7e0eda18c6f87feeb83628c707e8aaa3298b41fb72e38efe31ad1675f9e8e9',
'com.android.tools.analytics-library:tracker:26.1.3:tracker-26.1.3.jar:4155424bf2ce4872da83332579a1707252bc66cbd77c5144fdc4483d0f2e1418', 'com.android.tools.analytics-library:tracker:26.1.2:tracker-26.1.2.jar:06f97aa0adf44ffb06f8681c6a79d9be153a08f61d21eddc42b8d3db96df4282',
'com.android.tools.build:apksig:3.1.3:apksig-3.1.3.jar:7e1f8e675a6e768e5b56405e41d6c3cc05befe62e601b04177de1029902c9c89', 'com.android.tools.build:apksig:3.1.2:apksig-3.1.2.jar:40696a4559124d1d57873d208857eee059d48859239d569c7d18374ac644a8be',
'com.android.tools.build:builder-model:3.1.3:builder-model-3.1.3.jar:06ad1c422d679fc698451479cb40ba863849d67bfd1de23f6d2c16d78b024b0b', 'com.android.tools.build:builder-model:3.1.2:builder-model-3.1.2.jar:d49bfa2a135c9562b6ca7aa4342036cfa1582c7074c2d1d93d1dae8b3a134e17',
'com.android.tools.build:builder-test-api:3.1.3:builder-test-api-3.1.3.jar:4d989f780436794f0f8b2f50e9e079b786571eac90f26c208ab2ae6d4012f389', 'com.android.tools.build:builder-test-api:3.1.2:builder-test-api-3.1.2.jar:dfe2a50b740d41b11189101062434d4283d18647e89a492ad51710c719363e9f',
'com.android.tools.build:builder:3.1.3:builder-3.1.3.jar:8a1092012c89d0ec1ee2eff09c5708c71ef4482a6862df8d3a44a67fccace01c', 'com.android.tools.build:builder:3.1.2:builder-3.1.2.jar:b60f825a42e2efe8433619fbc759f3d9effecab718279048d36881188ceb1d14',
'com.android.tools.build:gradle-api:3.1.3:gradle-api-3.1.3.jar:01e4df521456aef66514336f1d492346730dd1fb8f6433a89f62da834941ed72', 'com.android.tools.build:gradle-api:3.1.2:gradle-api-3.1.2.jar:e58bcc5b893e4583ab0f5c8ef89c4dbcce202b405a9d7fcc116d21e5357d4893',
'com.android.tools.build:manifest-merger:26.1.3:manifest-merger-26.1.3.jar:1e4fc7e932adb4607082409800e5e6fccb42e6c5360ae5990094bf522f3ada55', 'com.android.tools.build:manifest-merger:26.1.2:manifest-merger-26.1.2.jar:9c61c27ea5266573107b954acf1216d398f4d7e7ae6fad6409d6b2b767eb091c',
'com.android.tools.ddms:ddmlib:26.1.3:ddmlib-26.1.3.jar:c54931cd68df5d1ea2923b3b320eae47cd2307a5a916bb8674c0acf93cd1d3cd', 'com.android.tools.ddms:ddmlib:26.1.2:ddmlib-26.1.2.jar:18a2a5fbef36882f07d03c2b9e59eba05cf8248177bf5cbff736e4b582804c44',
'com.android.tools.external.com-intellij:intellij-core:26.1.3:intellij-core-26.1.3.jar:af67f5535fef2e1a28b1007a4acb8c5deb6a1e33b8afe7b11d012c9e778ebcec', 'com.android.tools.external.com-intellij:intellij-core:26.1.2:intellij-core-26.1.2.jar:37c5acf279f1ae3e85b1a5be3c9f15f43bde7b08f978eefefffb9c4035760c52',
'com.android.tools.external.com-intellij:kotlin-compiler:26.1.3:kotlin-compiler-26.1.3.jar:c746d2859dc11cc05c84b692b3498d3a621e0929511f8440ee009c6557838fd4', 'com.android.tools.external.com-intellij:kotlin-compiler:26.1.2:kotlin-compiler-26.1.2.jar:152df0bee7580326c77316b669a9d96e3b09efb1d45f545dce4147271b0b8944',
'com.android.tools.external.org-jetbrains:uast:26.1.3:uast-26.1.3.jar:3f3f6651d0c7685a77ecb22e9c82d6b49fdf24322c17360768dc530678f43265', 'com.android.tools.external.org-jetbrains:uast:26.1.2:uast-26.1.2.jar:02d39582206d3f5fc0a6cb18bfd9e8b9f9c1acb805ec6dac08b4e3a56849d279',
'com.android.tools.layoutlib:layoutlib-api:26.1.3:layoutlib-api-26.1.3.jar:10bc73ce706c45629872d6a999dbe12116df64e24f47ff93b7b13121ff57b4b0', 'com.android.tools.layoutlib:layoutlib-api:26.1.2:layoutlib-api-26.1.2.jar:20220039fcc7d799f928153beff862e704457c0f55ab44258f3745ebeb662b4f',
'com.android.tools.lint:lint-api:26.1.3:lint-api-26.1.3.jar:6f97323f9af8deda86278717885b5c927f3766757db89709f52d11d42b6fb751', 'com.android.tools.lint:lint-api:26.1.2:lint-api-26.1.2.jar:e1d5b62b870a7c566e9877a6b96b27784a4d713f8caa07fdcb4705d47a40a1d9',
'com.android.tools.lint:lint-checks:26.1.3:lint-checks-26.1.3.jar:73c3d53784c9ce3e6d5968506581918e0179645d20809927ca4a001dd766b001', 'com.android.tools.lint:lint-checks:26.1.2:lint-checks-26.1.2.jar:211e2afd58504372385d71b1e5be982c2b5121ab6fee1c04ddabeb75a8729e07',
'com.android.tools.lint:lint-gradle-api:26.1.3:lint-gradle-api-26.1.3.jar:7ca3c4866ec21dc21d53a9d86f752b77ace6f6c610a0c9dc877313856c733d9d', 'com.android.tools.lint:lint-gradle-api:26.1.2:lint-gradle-api-26.1.2.jar:71284f2a8b03c3e55c94511c9eb36f8184fbb85324325fc6b78abf5183f03d90',
'com.android.tools.lint:lint-gradle:26.1.3:lint-gradle-26.1.3.jar:db0c354b8f4b6f6637e31f91c564785a59ff896325331fcbc3de7458e0b6c067', 'com.android.tools.lint:lint-gradle:26.1.2:lint-gradle-26.1.2.jar:855f0c82b7fc690df1b7319c0774f7517f7f8f5dd4eee1f6077dcf50e07c6240',
'com.android.tools.lint:lint-kotlin:26.1.3:lint-kotlin-26.1.3.jar:94e2b0f4565a241561cfb8fc1222bb3f132a3b98d2a90421dbb72ee8358e7d68', 'com.android.tools.lint:lint-kotlin:26.1.2:lint-kotlin-26.1.2.jar:1e591f70bcbbc11569720a9bbcca2bc1f3d4f789f01f40f642848d920643d484',
'com.android.tools.lint:lint:26.1.3:lint-26.1.3.jar:8d5f32c989c6d191d712e90ad3ca2d1c409313599551d04d834caa44d26c78df', 'com.android.tools.lint:lint:26.1.2:lint-26.1.2.jar:93736c62e9f1976998c2b4aa716aea0734cdb162d05502f4af7292654aedb182',
'com.android.tools:annotations:26.1.3:annotations-26.1.3.jar:c950430b24ac5d58fc97e7283b8f0115f99587e76e08b4e1e2aaa780f2d77323', 'com.android.tools:annotations:26.1.2:annotations-26.1.2.jar:72773dcaf5c4ccca828e3c8467f1b78a8a00b3cc5f8ad1aab88fcf9379928018',
'com.android.tools:common:26.1.3:common-26.1.3.jar:7c31a90581a148ab219f615a59667f0dded7fa39b248529784474da3c2274ef2', 'com.android.tools:common:26.1.2:common-26.1.2.jar:ea4320f0c17dcbc4491896bb705c4d25ec08bd62ef02ab0579fe154e75e788e6',
'com.android.tools:dvlib:26.1.3:dvlib-26.1.3.jar:0cae87906f53d3f1088366a916ed180a7312b6d9919b90797f238875c8492855', 'com.android.tools:dvlib:26.1.2:dvlib-26.1.2.jar:1187aa4fb666595c96c4deb6bc0e0f4b7e396bde9f6243330b49a232946130ea',
'com.android.tools:repository:26.1.3:repository-26.1.3.jar:52d4539cc68db91b261e2a33b2c8206b26e05539078758dc28cfb3854adb4f59', 'com.android.tools:repository:26.1.2:repository-26.1.2.jar:8b86e512ad6d32bd76989451eefe2b271f5efce6d4d65ecb173afaf14606e01a',
'com.android.tools:sdk-common:26.1.3:sdk-common-26.1.3.jar:1948603ca9ff22c7ebb3178000bffa3a9dd2ca1cc5cb0c793cae08468b8fcfc1', 'com.android.tools:sdk-common:26.1.2:sdk-common-26.1.2.jar:23584720a60a21cdcb5b1ec10269e3013789d6805d153cc696c39ec7ce251896',
'com.android.tools:sdklib:26.1.3:sdklib-26.1.3.jar:4adcfaad9514607098d2c51503c39811112d3050f4d1e744c01c7f08f591032b', 'com.android.tools:sdklib:26.1.2:sdklib-26.1.2.jar:d3870fafc59ab8efa70d3f9649f40ee299c8ec5b58377b06e8853d7272a5bf4e',
'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',
@@ -99,8 +92,6 @@ 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.16:tor-android-0.2.9.16.zip:515e33dda6a30853c885a2de2c79ae1ab9ad8b6db44f5db8890333ec2e24f4ae',
'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',
@@ -121,9 +112,81 @@ dependencyVerification {
] ]
} }
project.afterEvaluate { ext.torBinaryDir = 'src/main/res/raw'
copy { ext.torVersion = '0.2.9.14'
from configurations.tor.collect { zipTree(it) } ext.geoipVersion = '2017-11-06'
into 'src/main/res/raw' 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 {
torBinaries.every { name, checksum ->
preBuild.dependsOn.add(verifyBinary(name, checksum))
}
}
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.

View File

@@ -1,23 +0,0 @@
package org.briarproject.bramble;
import org.briarproject.bramble.event.EventModule;
import org.briarproject.bramble.plugin.PluginModule;
import org.briarproject.bramble.plugin.tor.BridgeTest;
import org.briarproject.bramble.system.SystemModule;
import javax.inject.Singleton;
import dagger.Component;
@Singleton
@Component(modules = {
BrambleAndroidModule.class,
PluginModule.class, // needed for BackoffFactory
EventModule.class,
SystemModule.class,
})
public interface IntegrationTestComponent {
void inject(BridgeTest init);
}

View File

@@ -1,126 +0,0 @@
package org.briarproject.bramble.plugin.tor;
import android.content.Context;
import android.support.test.runner.AndroidJUnit4;
import org.briarproject.bramble.DaggerIntegrationTestComponent;
import org.briarproject.bramble.IntegrationTestComponent;
import org.briarproject.bramble.api.event.EventBus;
import org.briarproject.bramble.api.plugin.BackoffFactory;
import org.briarproject.bramble.api.plugin.duplex.DuplexPlugin;
import org.briarproject.bramble.api.system.Clock;
import org.briarproject.bramble.api.system.LocationUtils;
import org.briarproject.bramble.test.BrambleTestCase;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.util.List;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.logging.Logger;
import javax.inject.Inject;
import javax.net.SocketFactory;
import static android.support.test.InstrumentationRegistry.getTargetContext;
import static java.util.Collections.singletonList;
import static java.util.concurrent.TimeUnit.SECONDS;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
@RunWith(AndroidJUnit4.class)
public class BridgeTest extends BrambleTestCase {
private final static long TIMEOUT = SECONDS.toMillis(23);
private final static Logger LOG =
Logger.getLogger(BridgeTest.class.getSimpleName());
@Inject
EventBus eventBus;
@Inject
BackoffFactory backoffFactory;
@Inject
Clock clock;
private final Context appContext = getTargetContext();
private final CircumventionProvider circumventionProvider;
private final List<String> bridges;
private TorPluginFactory factory;
private volatile int currentBridge = 0;
public BridgeTest() {
super();
circumventionProvider = new CircumventionProvider() {
@Override
public boolean isTorProbablyBlocked(String countryCode) {
return true;
}
@Override
public boolean doBridgesWork(String countryCode) {
return true;
}
@Override
public List<String> getBridges() {
return singletonList(bridges.get(currentBridge));
}
};
bridges = new CircumventionProviderImpl(appContext).getBridges();
}
@Before
public void setUp() {
IntegrationTestComponent component =
DaggerIntegrationTestComponent.builder().build();
component.inject(this);
Executor ioExecutor = Executors.newCachedThreadPool();
ScheduledExecutorService scheduler = new ScheduledThreadPoolExecutor(1);
LocationUtils locationUtils = () -> "US";
SocketFactory torSocketFactory = SocketFactory.getDefault();
factory = new TorPluginFactory(ioExecutor, scheduler, appContext,
locationUtils, eventBus, torSocketFactory,
backoffFactory, circumventionProvider, clock);
}
@Test
public void testBridges() throws Exception {
assertTrue(bridges.size() > 0);
for (int i = 0; i < bridges.size(); i++) {
testBridge(i);
}
}
private void testBridge(int bridge) throws Exception {
DuplexPlugin duplexPlugin =
factory.createPlugin(new TorPluginCallBack());
assertNotNull(duplexPlugin);
TorPlugin plugin = (TorPlugin) duplexPlugin;
currentBridge = bridge;
LOG.warning("Testing " + bridges.get(currentBridge));
try {
plugin.start();
long start = clock.currentTimeMillis();
while (clock.currentTimeMillis() - start < TIMEOUT) {
if (plugin.isRunning()) return;
clock.sleep(500);
}
if (!plugin.isRunning()) {
fail("Could not connect to Tor within timeout.");
}
} finally {
plugin.stop();
}
}
}

View File

@@ -1,54 +0,0 @@
package org.briarproject.bramble.plugin.tor;
import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.plugin.duplex.DuplexPluginCallback;
import org.briarproject.bramble.api.plugin.duplex.DuplexTransportConnection;
import org.briarproject.bramble.api.properties.TransportProperties;
import org.briarproject.bramble.api.settings.Settings;
@NotNullByDefault
public class TorPluginCallBack implements DuplexPluginCallback {
@Override
public void incomingConnectionCreated(DuplexTransportConnection d) {
}
@Override
public void outgoingConnectionCreated(ContactId c,
DuplexTransportConnection d) {
}
@Override
public Settings getSettings() {
return new Settings();
}
@Override
public TransportProperties getLocalProperties() {
return new TransportProperties();
}
@Override
public void mergeSettings(Settings s) {
}
@Override
public void mergeLocalProperties(TransportProperties p) {
}
@Override
public void transportEnabled() {
}
@Override
public void transportDisabled() {
}
}

View File

@@ -2,13 +2,14 @@
package="org.briarproject.bramble" package="org.briarproject.bramble"
xmlns:android="http://schemas.android.com/apk/res/android"> xmlns:android="http://schemas.android.com/apk/res/android">
<uses-feature android:name="android.hardware.bluetooth" android:required="false"/> <uses-feature android:name="android.hardware.bluetooth"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.BLUETOOTH"/> <uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
<uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.READ_LOGS"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/> <uses-permission android:name="android.permission.WAKE_LOCK"/>
<application <application

View File

@@ -1,25 +1,13 @@
package org.briarproject.bramble; package org.briarproject.bramble;
import android.app.Application; import org.briarproject.bramble.plugin.AndroidPluginModule;
import org.briarproject.bramble.plugin.tor.CircumventionProvider;
import org.briarproject.bramble.plugin.tor.CircumventionProviderImpl;
import org.briarproject.bramble.system.AndroidSystemModule; import org.briarproject.bramble.system.AndroidSystemModule;
import javax.inject.Singleton;
import dagger.Module; import dagger.Module;
import dagger.Provides;
@Module(includes = { @Module(includes = {
AndroidPluginModule.class,
AndroidSystemModule.class AndroidSystemModule.class
}) })
public class BrambleAndroidModule { public class BrambleAndroidModule {
@Provides
@Singleton
CircumventionProvider provideCircumventionProvider(Application app) {
return new CircumventionProviderImpl(app.getApplicationContext());
}
} }

View File

@@ -0,0 +1,69 @@
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;
}
}

View File

@@ -38,7 +38,6 @@ 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
@@ -146,7 +145,7 @@ class AndroidBluetoothPlugin extends BluetoothPlugin<BluetoothServerSocket> {
try { try {
if (ss != null) ss.close(); if (ss != null) ss.close();
} catch (IOException e) { } catch (IOException e) {
logException(LOG, WARNING, e); if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
} }
} }
@@ -186,7 +185,7 @@ class AndroidBluetoothPlugin extends BluetoothPlugin<BluetoothServerSocket> {
try { try {
if (c != null) c.close(); if (c != null) c.close();
} catch (IOException e) { } catch (IOException e) {
logException(LOG, WARNING, e); if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
} }
} }

View File

@@ -1,30 +0,0 @@
package org.briarproject.bramble.plugin.tor;
import org.briarproject.bramble.api.lifecycle.IoExecutor;
import java.util.List;
public interface CircumventionProvider {
/**
* Countries where Tor is blocked, i.e. vanilla Tor connection won't work.
*
* See https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2
* and https://trac.torproject.org/projects/tor/wiki/doc/OONI/censorshipwiki
*/
String[] BLOCKED = {"CN", "IR", "EG", "BY", "TR", "SY", "VE"};
/**
* Countries where vanilla bridge connection are likely to work.
* Should be a subset of {@link #BLOCKED}.
*/
String[] BRIDGES = { "EG", "BY", "TR", "SY", "VE" };
boolean isTorProbablyBlocked(String countryCode);
boolean doBridgesWork(String countryCode);
@IoExecutor
List<String> getBridges();
}

View File

@@ -1,68 +0,0 @@
package org.briarproject.bramble.plugin.tor;
import android.content.Context;
import android.content.res.Resources;
import org.briarproject.bramble.api.lifecycle.IoExecutor;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Scanner;
import java.util.Set;
import javax.annotation.Nullable;
import javax.inject.Inject;
public class CircumventionProviderImpl implements CircumventionProvider {
private final static String BRIDGE_FILE_NAME = "bridges";
private final Context ctx;
@Nullable
private volatile List<String> bridges = null;
@Inject
public CircumventionProviderImpl(Context ctx) {
this.ctx = ctx;
}
private static final Set<String> BLOCKED_IN_COUNTRIES =
new HashSet<>(Arrays.asList(BLOCKED));
private static final Set<String> BRIDGES_WORK_IN_COUNTRIES =
new HashSet<>(Arrays.asList(BRIDGES));
@Override
public boolean isTorProbablyBlocked(String countryCode) {
return BLOCKED_IN_COUNTRIES.contains(countryCode);
}
@Override
public boolean doBridgesWork(String countryCode) {
return BRIDGES_WORK_IN_COUNTRIES.contains(countryCode);
}
@Override
@IoExecutor
public List<String> getBridges() {
if (this.bridges != null) return this.bridges;
Resources res = ctx.getResources();
int resId = res.getIdentifier(BRIDGE_FILE_NAME, "raw",
ctx.getPackageName());
InputStream is = ctx.getResources().openRawResource(resId);
Scanner scanner = new Scanner(is);
List<String> bridges = new ArrayList<>();
while (scanner.hasNextLine()) {
String line = scanner.nextLine();
if (!line.startsWith("#")) bridges.add(line);
}
scanner.close();
this.bridges = bridges;
return bridges;
}
}

View File

@@ -0,0 +1,18 @@
package org.briarproject.bramble.plugin.tor;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
class TorNetworkMetadata {
// See https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2
// and https://trac.torproject.org/projects/tor/wiki/doc/OONI/censorshipwiki
// TODO: get a more complete list
private static final Set<String> BLOCKED_IN_COUNTRIES =
new HashSet<>(Arrays.asList("CN", "IR", "SY", "ZZ"));
static boolean isTorProbablyBlocked(String countryCode) {
return BLOCKED_IN_COUNTRIES.contains(countryCode);
}
}

View File

@@ -10,6 +10,7 @@ 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;
@@ -31,12 +32,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;
@@ -50,7 +51,6 @@ import java.io.OutputStream;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.net.ServerSocket; import java.net.ServerSocket;
import java.net.Socket; import java.net.Socket;
import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
@@ -58,6 +58,7 @@ 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;
@@ -80,6 +81,7 @@ 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;
@@ -93,7 +95,6 @@ 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
@@ -104,11 +105,8 @@ 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_MS = 3000; private static final int COOKIE_TIMEOUT = 3000; // Milliseconds
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());
@@ -116,17 +114,16 @@ 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;
private final CircumventionProvider circumventionProvider;
private final int maxLatency, maxIdleTime, socketTimeout; private final int maxLatency, maxIdleTime, socketTimeout;
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 RenewableWakeLock wakeLock; private final PowerManager.WakeLock 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);
@@ -139,19 +136,18 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
TorPlugin(Executor ioExecutor, ScheduledExecutorService scheduler, TorPlugin(Executor ioExecutor, ScheduledExecutorService scheduler,
Context appContext, LocationUtils locationUtils, Context appContext, LocationUtils locationUtils,
SocketFactory torSocketFactory, Clock clock, Backoff backoff, DevReporter reporter, SocketFactory torSocketFactory,
DuplexPluginCallback callback, String architecture, Backoff backoff, DuplexPluginCallback callback,
CircumventionProvider circumventionProvider, int maxLatency, int maxIdleTime) { String architecture, 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;
this.circumventionProvider = circumventionProvider;
this.maxLatency = maxLatency; this.maxLatency = maxLatency;
this.maxIdleTime = maxIdleTime; this.maxIdleTime = maxIdleTime;
if (maxIdleTime > Integer.MAX_VALUE / 2) if (maxIdleTime > Integer.MAX_VALUE / 2)
@@ -164,13 +160,14 @@ 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
@@ -193,10 +190,18 @@ 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();
if (cookieFile.exists() && !cookieFile.delete())
LOG.warning("Old auth cookie not deleted");
// Start a new Tor process
LOG.info("Starting Tor"); LOG.info("Starting Tor");
// Watch for the auth cookie file being updated
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
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());
@@ -235,16 +240,11 @@ 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
long start = clock.currentTimeMillis(); if (!latch.await(COOKIE_TIMEOUT, MILLISECONDS)) {
while (cookieFile.length() < 32) { LOG.warning("Auth cookie not created");
if (clock.currentTimeMillis() - start > COOKIE_TIMEOUT_MS) { if (LOG.isLoggable(INFO)) listFiles(torDirectory);
LOG.warning("Auth cookie not created"); throw new PluginException();
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 +338,7 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
return zin; return zin;
} }
private InputStream getConfigInputStream() { private InputStream getConfigInputStream() throws IOException {
int resId = getResourceId("torrc"); int resId = getResourceId("torrc");
return appContext.getResources().openRawResource(resId); return appContext.getResources().openRawResource(resId);
} }
@@ -352,7 +352,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) {
logException(LOG, WARNING, e); if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
} }
} }
@@ -360,7 +360,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) {
logException(LOG, WARNING, e); if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
} }
} }
@@ -369,7 +369,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() + " " + f.length()); LOG.info(f.getAbsolutePath());
} }
} }
@@ -389,6 +389,14 @@ 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
@@ -402,7 +410,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) {
logException(LOG, WARNING, e); if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
tryToClose(ss); tryToClose(ss);
return; return;
} }
@@ -428,7 +436,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) {
logException(LOG, WARNING, e); if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
} finally { } finally {
callback.transportDisabled(); callback.transportDisabled();
} }
@@ -447,7 +455,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) {
logException(LOG, WARNING, e); if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
return; return;
} }
if (!response.containsKey(HS_ADDRESS)) { if (!response.containsKey(HS_ADDRESS)) {
@@ -502,19 +510,8 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
} }
} }
private void enableBridges(boolean enable) throws IOException {
if (enable) {
Collection<String> conf = new ArrayList<>();
conf.add("UseBridges 1");
conf.addAll(circumventionProvider.getBridges());
controlConnection.setConf(conf);
} else {
controlConnection.setConf("UseBridges", "0");
}
}
@Override @Override
public void stop() { public void stop() throws PluginException {
running = false; running = false;
tryToClose(socket); tryToClose(socket);
if (networkStateReceiver != null) if (networkStateReceiver != null)
@@ -526,7 +523,7 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
controlConnection.shutdownTor("TERM"); controlConnection.shutdownTor("TERM");
controlSocket.close(); controlSocket.close();
} catch (IOException e) { } catch (IOException e) {
logException(LOG, WARNING, e); if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
} }
} }
wakeLock.release(); wakeLock.release();
@@ -548,16 +545,20 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
} }
@Override @Override
public void poll(Map<ContactId, TransportProperties> contacts) { public void poll(Collection<ContactId> connected) {
if (!isRunning()) return; if (!isRunning()) return;
backoff.increment(); backoff.increment();
for (Entry<ContactId, TransportProperties> e : contacts.entrySet()) { Map<ContactId, TransportProperties> remote =
connectAndCallBack(e.getKey(), e.getValue()); callback.getRemoteProperties();
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();
@@ -567,8 +568,13 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
} }
@Override @Override
public DuplexTransportConnection createConnection(TransportProperties p) { public DuplexTransportConnection createConnection(ContactId c) {
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()) {
@@ -618,7 +624,10 @@ 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()) callback.transportEnabled(); if (isRunning()) {
sendDevReports();
callback.transportEnabled();
}
} }
} }
@@ -647,7 +656,10 @@ 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()) callback.transportEnabled(); if (isRunning()) {
sendDevReports();
callback.transportEnabled();
}
} }
} }
@@ -657,6 +669,22 @@ 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) {
@@ -677,8 +705,8 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
boolean online = net != null && net.isConnected(); boolean online = net != null && net.isConnected();
boolean wifi = online && net.getType() == TYPE_WIFI; boolean wifi = online && net.getType() == TYPE_WIFI;
String country = locationUtils.getCurrentCountry(); String country = locationUtils.getCurrentCountry();
boolean blocked = boolean blocked = TorNetworkMetadata.isTorProbablyBlocked(
circumventionProvider.isTorProbablyBlocked(country); country);
Settings s = callback.getSettings(); Settings s = callback.getSettings();
int network = s.getInt(PREF_TOR_NETWORK, PREF_TOR_NETWORK_ALWAYS); int network = s.getInt(PREF_TOR_NETWORK, PREF_TOR_NETWORK_ALWAYS);
@@ -692,26 +720,19 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
if (!online) { if (!online) {
LOG.info("Disabling network, device is offline"); LOG.info("Disabling network, device is offline");
enableNetwork(false); enableNetwork(false);
} else if (blocked) {
LOG.info("Disabling network, country is blocked");
enableNetwork(false);
} else if (network == PREF_TOR_NETWORK_NEVER } else if (network == PREF_TOR_NETWORK_NEVER
|| (network == PREF_TOR_NETWORK_WIFI && !wifi)) { || (network == PREF_TOR_NETWORK_WIFI && !wifi)) {
LOG.info("Disabling network due to data setting"); LOG.info("Disabling network due to data setting");
enableNetwork(false); enableNetwork(false);
} else if (blocked) {
if (circumventionProvider.doBridgesWork(country)) {
LOG.info("Enabling network, using bridges");
enableBridges(true);
enableNetwork(true);
} else {
LOG.info("Disabling network, country is blocked");
enableNetwork(false);
}
} else { } else {
LOG.info("Enabling network"); LOG.info("Enabling network");
enableBridges(false);
enableNetwork(true); enableNetwork(true);
} }
} catch (IOException e) { } catch (IOException e) {
logException(LOG, WARNING, e); if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
} }
}); });
} }

View File

@@ -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.system.Clock; import org.briarproject.bramble.api.reporting.DevReporter;
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,27 +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 CircumventionProvider circumventionProvider;
private final Clock clock;
public TorPluginFactory(Executor ioExecutor, public TorPluginFactory(Executor ioExecutor,
ScheduledExecutorService scheduler, Context appContext, ScheduledExecutorService scheduler, Context appContext,
LocationUtils locationUtils, EventBus eventBus, LocationUtils locationUtils, DevReporter reporter,
SocketFactory torSocketFactory, BackoffFactory backoffFactory, EventBus eventBus, SocketFactory torSocketFactory,
CircumventionProvider circumventionProvider, 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.circumventionProvider = circumventionProvider;
this.clock = clock;
} }
@Override @Override
@@ -97,8 +94,8 @@ 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, torSocketFactory, clock, backoff, callback, locationUtils, reporter, torSocketFactory, backoff, callback,
architecture, circumventionProvider, MAX_LATENCY, MAX_IDLE_TIME); architecture, MAX_LATENCY, MAX_IDLE_TIME);
eventBus.addListener(plugin); eventBus.addListener(plugin);
return plugin; return plugin;
} }

View File

@@ -9,7 +9,6 @@ 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;
@@ -67,12 +66,9 @@ 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

View File

@@ -1,9 +1,7 @@
package org.briarproject.bramble.util; package org.briarproject.bramble.util;
import android.annotation.SuppressLint;
import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothAdapter;
import android.content.Context; import android.content.Context;
import android.content.SharedPreferences;
import android.os.Build; import android.os.Build;
import android.provider.Settings; import android.provider.Settings;
@@ -12,15 +10,11 @@ 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.logging.Logger;
import static android.content.Context.MODE_PRIVATE; import static android.content.Context.MODE_PRIVATE;
public class AndroidUtils { public class AndroidUtils {
private static final Logger LOG =
Logger.getLogger(AndroidUtils.class.getName());
// Fake Bluetooth address returned by BluetoothAdapter on API 23 and later // Fake Bluetooth address returned by BluetoothAdapter on API 23 and later
private static final String FAKE_BLUETOOTH_ADDRESS = "02:00:00:00:00:00"; private static final String FAKE_BLUETOOTH_ADDRESS = "02:00:00:00:00:00";
@@ -41,7 +35,6 @@ public class AndroidUtils {
public static String getBluetoothAddress(Context ctx, public static String getBluetoothAddress(Context ctx,
BluetoothAdapter adapter) { BluetoothAdapter adapter) {
// Return the adapter's address if it's valid and not fake // Return the adapter's address if it's valid and not fake
@SuppressLint("HardwareIds")
String address = adapter.getAddress(); String address = adapter.getAddress();
if (isValidBluetoothAddress(address)) return address; if (isValidBluetoothAddress(address)) return address;
// Return the address from settings if it's valid and not fake // Return the address from settings if it's valid and not fake
@@ -58,28 +51,17 @@ public class AndroidUtils {
&& !address.equals(FAKE_BLUETOOTH_ADDRESS); && !address.equals(FAKE_BLUETOOTH_ADDRESS);
} }
public static void deleteAppData(Context ctx, SharedPreferences... clear) { public static void deleteAppData(Context ctx) {
// Clear and commit shared preferences
for (SharedPreferences prefs : clear) {
if (!prefs.edit().clear().commit())
LOG.warning("Could not clear shared preferences");
}
// Delete files, except lib and shared_prefs directories
File dataDir = new File(ctx.getApplicationInfo().dataDir); File dataDir = new File(ctx.getApplicationInfo().dataDir);
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(); if (!child.getName().equals("lib"))
if (!name.equals("lib") && !name.equals("shared_prefs")) {
IoUtils.deleteFileOrDir(child); IoUtils.deleteFileOrDir(child);
}
} }
} }
// Recreate the cache dir as some OpenGL drivers expect it to exist // Recreate the cache dir as some OpenGL drivers expect it to exist
if (!new File(dataDir, "cache").mkdir()) new File(dataDir, "cache").mkdir();
LOG.warning("Could not recreate cache dir");
} }
public static File getReportDir(Context ctx) { public static File getReportDir(Context ctx) {

View File

@@ -1,100 +0,0 @@
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;
}
}
}

View File

@@ -1,8 +0,0 @@
Bridge 131.252.210.150:8081 0E858AC201BF0F3FA3C462F64844CBFFC7297A42
Bridge 67.205.189.122:8443 12D64D5D44E20169585E7378580C0D33A872AD98
Bridge 45.32.148.146:8443 0CE016FB2462D8BF179AE71F7D702D09DEAC3F1D
Bridge 148.251.90.59:7510 019F727CA6DCA6CA5C90B55E477B7D87981E75BC
Bridge 195.91.239.8:9001 BA83F62551545655BBEBBFF353A45438D73FD45A
Bridge 185.165.184.217:6429 64CC94BEC51254E4409AD059192833854CCB95F0
Bridge 45.55.1.74:8443 6F18FEFBB0CAECD5ABA755312FCCB34FC11A7AB8
Bridge 95.85.40.163:9001 40057BE9CF76B6C5BDBE713753468BE0A990DE9C

View File

@@ -2,7 +2,6 @@ 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 {
@@ -15,8 +14,6 @@ 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 {
@@ -29,9 +26,6 @@ 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',
@@ -39,7 +33,6 @@ 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',
] ]
} }
@@ -55,3 +48,8 @@ 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)
}

View File

@@ -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, SecretKey master, ContactId addContact(Author remote, AuthorId local,
long timestamp, boolean alice, boolean verified, boolean active) SecretKey master, long timestamp, boolean alice, boolean verified,
throws DbException; boolean active) throws DbException;
/** /**
* Returns the contact with the given ID. * Returns the contact with the given ID.

View File

@@ -5,7 +5,7 @@ import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.concurrent.Immutable; import javax.annotation.concurrent.Immutable;
/** /**
* A key pair consisting of a {@link PublicKey} and a {@link PrivateKey}. * A key pair consisting of a {@link PublicKey} and a {@link PrivateKey).
*/ */
@Immutable @Immutable
@NotNullByDefault @NotNullByDefault

View File

@@ -8,7 +8,6 @@ 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;
@@ -40,13 +39,13 @@ public interface BdfReader {
boolean hasString() throws IOException; boolean hasString() throws IOException;
String readString() throws IOException; String readString(int maxLength) throws IOException;
void skipString() throws IOException; void skipString() throws IOException;
boolean hasRaw() throws IOException; boolean hasRaw() throws IOException;
byte[] readRaw() throws IOException; byte[] readRaw(int maxLength) throws IOException;
void skipRaw() throws IOException; void skipRaw() throws IOException;

View File

@@ -9,6 +9,5 @@ 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);
} }

View File

@@ -104,12 +104,18 @@ public interface DatabaseComponent {
throws DbException; throws DbException;
/** /**
* Stores the given transport keys for the given contact and returns a * Stores the given transport keys, optionally binding them to the given
* key set ID. * contact, and returns a key set ID.
*/ */
KeySetId addTransportKeys(Transaction txn, ContactId c, KeySetId addTransportKeys(Transaction txn, @Nullable 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.

View File

@@ -14,8 +14,6 @@ public interface DatabaseConfig {
File getDatabaseDirectory(); File getDatabaseDirectory();
File getDatabaseKeyDirectory();
void setEncryptionKey(SecretKey key); void setEncryptionKey(SecretKey key);
@Nullable @Nullable

View File

@@ -12,7 +12,7 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
/** /**
* Annotation for injecting the executor for long-running IO tasks. Also used * Annotation for injecting the executor for long-running IO tasks. Also used
* for annotating methods that should run on the IO executor. * for annotating methods that should run on the UI executor.
* <p> * <p>
* The contract of this executor is that tasks may be run concurrently, and * The contract of this executor is that tasks may be run concurrently, and
* submitting a task will never block. Tasks may run indefinitely. Tasks * submitting a task will never block. Tasks may run indefinitely. Tasks

View File

@@ -1,6 +0,0 @@
package org.briarproject.bramble.api.plugin;
public interface FileConstants {
String PROP_PATH = "path";
}

View File

@@ -2,9 +2,8 @@ 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.Map; import java.util.Collection;
@NotNullByDefault @NotNullByDefault
public interface Plugin { public interface Plugin {
@@ -40,19 +39,21 @@ public interface Plugin {
boolean isRunning(); boolean isRunning();
/** /**
* Returns true if the plugin should be polled periodically to attempt to * Returns true if the plugin's {@link #poll(Collection)} method should be
* establish connections. * called periodically to attempt to establish connections.
*/ */
boolean shouldPoll(); boolean shouldPoll();
/** /**
* Returns the desired interval in milliseconds between polling attempts. * Returns the desired interval in milliseconds between calls to the
* plugin's {@link #poll(Collection)} method.
*/ */
int getPollingInterval(); int getPollingInterval();
/** /**
* Attempts to establish connections to the given contacts, passing any * Attempts to establish connections to contacts, passing any created
* created connections to the callback. * connections to the callback. To avoid creating redundant connections,
* the plugin may exclude the given contacts from polling.
*/ */
void poll(Map<ContactId, TransportProperties> contacts); void poll(Collection<ContactId> connected);
} }

View File

@@ -1,9 +1,12 @@
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.
@@ -22,7 +25,17 @@ public interface PluginCallback {
TransportProperties getLocalProperties(); TransportProperties getLocalProperties();
/** /**
* Merges the given settings with the plugin's settings * Returns the plugin's remote transport properties.
*/
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);
@@ -32,12 +45,34 @@ public interface PluginCallback {
void mergeLocalProperties(TransportProperties p); void mergeLocalProperties(TransportProperties p);
/** /**
* Signals that the transport is enabled. * 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);
/**
* Signal that the transport got enabled.
*/ */
void transportEnabled(); void transportEnabled();
/** /**
* Signals that the transport is disabled. * Signal that the transport got disabled.
*/ */
void transportDisabled(); void transportDisabled();
} }

View File

@@ -12,6 +12,4 @@ public interface PluginConfig {
Collection<DuplexPluginFactory> getDuplexFactories(); Collection<DuplexPluginFactory> getDuplexFactories();
Collection<SimplexPluginFactory> getSimplexFactories(); Collection<SimplexPluginFactory> getSimplexFactories();
boolean shouldPoll();
} }

View File

@@ -22,6 +22,11 @@ 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.
*/ */

View File

@@ -71,6 +71,11 @@ 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();

View File

@@ -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,11 +15,12 @@ import javax.annotation.Nullable;
public interface DuplexPlugin extends Plugin { public interface DuplexPlugin extends Plugin {
/** /**
* Attempts to create and return a connection using the given transport * Attempts to create and return a connection to the given contact using
* properties. Returns null if a connection cannot be created. * the current transport and configuration properties. Returns null if a
* connection cannot be created.
*/ */
@Nullable @Nullable
DuplexTransportConnection createConnection(TransportProperties p); DuplexTransportConnection createConnection(ContactId c);
/** /**
* Returns true if the plugin supports short-range key agreement. * Returns true if the plugin supports short-range key agreement.

View File

@@ -5,8 +5,7 @@ import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.plugin.PluginCallback; import org.briarproject.bramble.api.plugin.PluginCallback;
/** /**
* An interface through which a duplex plugin interacts with the rest of the * An interface for handling connections created by a duplex transport plugin.
* application.
*/ */
@NotNullByDefault @NotNullByDefault
public interface DuplexPluginCallback extends PluginCallback { public interface DuplexPluginCallback extends PluginCallback {

View File

@@ -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,16 +15,18 @@ import javax.annotation.Nullable;
public interface SimplexPlugin extends Plugin { public interface SimplexPlugin extends Plugin {
/** /**
* Attempts to create and return a reader for the given transport * Attempts to create and return a reader for the given contact using the
* properties. Returns null if a reader cannot be created. * current transport and configuration properties. Returns null if a reader
* cannot be created.
*/ */
@Nullable @Nullable
TransportConnectionReader createReader(TransportProperties p); TransportConnectionReader createReader(ContactId c);
/** /**
* Attempts to create and return a writer for the given transport * Attempts to create and return a writer for the given contact using the
* properties. Returns null if a writer cannot be created. * current transport and configuration properties. Returns null if a writer
* cannot be created.
*/ */
@Nullable @Nullable
TransportConnectionWriter createWriter(TransportProperties p); TransportConnectionWriter createWriter(ContactId c);
} }

View File

@@ -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 through which a simplex plugin interacts with the rest of the * An interface for handling readers and writers created by a simplex transport
* application. * plugin.
*/ */
@NotNullByDefault @NotNullByDefault
public interface SimplexPluginCallback extends PluginCallback { public interface SimplexPluginCallback extends PluginCallback {

View File

@@ -3,14 +3,10 @@ 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();
} }

View File

@@ -23,6 +23,8 @@ 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(); void sendReports(File reportDir);
} }

View File

@@ -2,9 +2,9 @@ package org.briarproject.bramble.api.sync;
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.transport.StreamWriter;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream;
@NotNullByDefault @NotNullByDefault
public interface SyncSessionFactory { public interface SyncSessionFactory {
@@ -12,8 +12,8 @@ public interface SyncSessionFactory {
SyncSession createIncomingSession(ContactId c, InputStream in); SyncSession createIncomingSession(ContactId c, InputStream in);
SyncSession createSimplexOutgoingSession(ContactId c, int maxLatency, SyncSession createSimplexOutgoingSession(ContactId c, int maxLatency,
StreamWriter streamWriter); OutputStream out);
SyncSession createDuplexOutgoingSession(ContactId c, int maxLatency, SyncSession createDuplexOutgoingSession(ContactId c, int maxLatency,
int maxIdleTime, StreamWriter streamWriter); int maxIdleTime, OutputStream out);
} }

View File

@@ -7,12 +7,12 @@ package org.briarproject.bramble.api.system;
public interface Clock { public interface Clock {
/** /**
* @see System#currentTimeMillis() * @see {@link System#currentTimeMillis()}
*/ */
long currentTimeMillis(); long currentTimeMillis();
/** /**
* @see Thread#sleep(long) * @see {@link Thread#sleep(long)}
*/ */
void sleep(long milliseconds) throws InterruptedException; void sleep(long milliseconds) throws InterruptedException;
} }

View File

@@ -19,24 +19,48 @@ 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 and returns the key set IDs. * each transport.
* <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
*/ */
Map<TransportId, KeySetId> addContact(Transaction txn, ContactId c, void addContact(Transaction txn, ContactId c, SecretKey master,
SecretKey master, long timestamp, boolean alice, boolean active) long timestamp, boolean alice) throws DbException;
/**
* 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. * Marks the given transport keys as usable for outgoing streams. Keys must
* 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.

View File

@@ -3,20 +3,23 @@ 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. * A set of transport keys for communicating with a contact. If the keys have
* 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, ContactId contactId, public KeySet(KeySetId keySetId, @Nullable ContactId contactId,
TransportKeys transportKeys) { TransportKeys transportKeys) {
this.keySetId = keySetId; this.keySetId = keySetId;
this.contactId = contactId; this.contactId = contactId;
@@ -27,6 +30,7 @@ public class KeySet {
return keySetId; return keySetId;
} }
@Nullable
public ContactId getContactId() { public ContactId getContactId() {
return contactId; return contactId;
} }

View File

@@ -1,19 +0,0 @@
package org.briarproject.bramble.api.transport;
import java.io.IOException;
import java.io.OutputStream;
/**
* An interface for writing data to a transport connection. Data will be
* encrypted and authenticated before being written to the connection.
*/
public interface StreamWriter {
OutputStream getOutputStream();
/**
* Sends the end of stream marker, informing the recipient that no more
* data will be sent. The connection is flushed but not closed.
*/
void sendEndOfStream() throws IOException;
}

View File

@@ -12,12 +12,12 @@ public interface StreamWriterFactory {
* Creates an {@link OutputStream OutputStream} for writing to a * Creates an {@link OutputStream OutputStream} for writing to a
* transport stream * transport stream
*/ */
StreamWriter createStreamWriter(OutputStream out, StreamContext ctx); OutputStream createStreamWriter(OutputStream out, StreamContext ctx);
/** /**
* Creates an {@link OutputStream OutputStream} for writing to a contact * Creates an {@link OutputStream OutputStream} for writing to a contact
* exchange stream. * exchange stream.
*/ */
StreamWriter createContactExchangeStreamWriter(OutputStream out, OutputStream createContactExchangeStreamWriter(OutputStream out,
SecretKey headerKey); SecretKey headerKey);
} }

View File

@@ -0,0 +1,26 @@
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);
}

View File

@@ -9,40 +9,25 @@ import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.net.Socket; import java.net.Socket;
import java.util.logging.Logger;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import static java.util.logging.Level.WARNING;
@NotNullByDefault @NotNullByDefault
public class IoUtils { public class IoUtils {
private static final Logger LOG = Logger.getLogger(IoUtils.class.getName());
public static void deleteFileOrDir(File f) { public static void deleteFileOrDir(File f) {
if (f.isFile()) { if (f.isFile()) {
delete(f); f.delete();
} 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);
} f.delete();
delete(f);
} }
} }
private static void delete(File f) { public static void copyAndClose(InputStream in, OutputStream out)
if (!f.delete() && LOG.isLoggable(WARNING)) throws IOException {
LOG.warning("Could not delete " + f.getAbsolutePath());
}
public static void copyAndClose(InputStream in, OutputStream out) {
byte[] buf = new byte[4096]; byte[] buf = new byte[4096];
try { try {
while (true) { while (true) {

View File

@@ -1,36 +0,0 @@
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);
}
}

View File

@@ -22,6 +22,19 @@ 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();
} }

View File

@@ -2,7 +2,6 @@ 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'
@@ -27,8 +26,6 @@ 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 {
@@ -47,9 +44,6 @@ 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',
@@ -58,7 +52,6 @@ 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',
] ]
@@ -75,3 +68,8 @@ 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)
}

View File

@@ -7,7 +7,6 @@ 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;
@@ -29,8 +28,6 @@ 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);

View File

@@ -59,7 +59,6 @@ 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());

View File

@@ -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,6 +20,8 @@ import static org.briarproject.bramble.util.LogUtils.now;
@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<>();
@@ -47,11 +49,11 @@ public class PoliteExecutor implements Executor {
@Override @Override
public void execute(Runnable r) { public void execute(Runnable r) {
long submitted = now(); long submitted = System.currentTimeMillis();
Runnable wrapped = () -> { Runnable wrapped = () -> {
if (log.isLoggable(FINE)) { if (log.isLoggable(LOG_LEVEL)) {
long queued = now() - submitted; long queued = System.currentTimeMillis() - submitted;
log.fine("Queue time " + queued + " ms"); log.log(LOG_LEVEL, "Queue time " + queued + " ms");
} }
try { try {
r.run(); r.run();

View File

@@ -6,14 +6,16 @@ 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,
@@ -27,15 +29,15 @@ public class TimeLoggingExecutor extends ThreadPoolExecutor {
@Override @Override
public void execute(Runnable r) { public void execute(Runnable r) {
if (log.isLoggable(FINE)) { if (log.isLoggable(LOG_LEVEL)) {
long submitted = now(); long submitted = System.currentTimeMillis();
super.execute(() -> { super.execute(() -> {
long started = now(); long started = System.currentTimeMillis();
long queued = started - submitted; long queued = started - submitted;
log.fine("Queue time " + queued + " ms"); log.log(LOG_LEVEL, "Queue time " + queued + " ms");
r.run(); r.run();
long executing = now() - started; long executing = System.currentTimeMillis() - started;
log.fine("Execution time " + executing + " ms"); log.log(LOG_LEVEL, "Execution time " + executing + " ms");
}); });
} else { } else {
super.execute(r); super.execute(r);

View File

@@ -30,7 +30,6 @@ import org.briarproject.bramble.api.record.RecordWriter;
import org.briarproject.bramble.api.record.RecordWriterFactory; import org.briarproject.bramble.api.record.RecordWriterFactory;
import org.briarproject.bramble.api.system.Clock; import org.briarproject.bramble.api.system.Clock;
import org.briarproject.bramble.api.transport.StreamReaderFactory; import org.briarproject.bramble.api.transport.StreamReaderFactory;
import org.briarproject.bramble.api.transport.StreamWriter;
import org.briarproject.bramble.api.transport.StreamWriterFactory; import org.briarproject.bramble.api.transport.StreamWriterFactory;
import java.io.EOFException; import java.io.EOFException;
@@ -46,7 +45,6 @@ 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;
@@ -123,7 +121,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) {
logException(LOG, WARNING, e); if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
listener.contactExchangeFailed(); listener.contactExchangeFailed();
tryToClose(conn); tryToClose(conn);
return; return;
@@ -134,7 +132,7 @@ class ContactExchangeTaskImpl extends Thread implements ContactExchangeTask {
try { try {
localProperties = transportPropertyManager.getLocalProperties(); localProperties = transportPropertyManager.getLocalProperties();
} catch (DbException e) { } catch (DbException e) {
logException(LOG, WARNING, e); if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
listener.contactExchangeFailed(); listener.contactExchangeFailed();
tryToClose(conn); tryToClose(conn);
return; return;
@@ -154,11 +152,11 @@ class ContactExchangeTaskImpl extends Thread implements ContactExchangeTask {
recordReaderFactory.createRecordReader(streamReader); recordReaderFactory.createRecordReader(streamReader);
// Create the writers // Create the writers
StreamWriter streamWriter = OutputStream streamWriter =
streamWriterFactory.createContactExchangeStreamWriter(out, streamWriterFactory.createContactExchangeStreamWriter(out,
alice ? aliceHeaderKey : bobHeaderKey); alice ? aliceHeaderKey : bobHeaderKey);
RecordWriter recordWriter = RecordWriter recordWriter =
recordWriterFactory.createRecordWriter(streamWriter.getOutputStream()); recordWriterFactory.createRecordWriter(streamWriter);
// Derive the nonces to be signed // Derive the nonces to be signed
byte[] aliceNonce = crypto.mac(ALICE_NONCE_LABEL, masterSecret, byte[] aliceNonce = crypto.mac(ALICE_NONCE_LABEL, masterSecret,
@@ -186,8 +184,8 @@ class ContactExchangeTaskImpl extends Thread implements ContactExchangeTask {
localSignature, localTimestamp); localSignature, localTimestamp);
recordWriter.flush(); recordWriter.flush();
} }
// Send EOF on the outgoing stream // Close the outgoing stream
streamWriter.sendEndOfStream(); recordWriter.close();
// Skip any remaining records from the incoming stream // Skip any remaining records from the incoming stream
try { try {
while (true) recordReader.readRecord(); while (true) recordReader.readRecord();
@@ -195,7 +193,7 @@ class ContactExchangeTaskImpl extends Thread implements ContactExchangeTask {
LOG.info("End of stream"); LOG.info("End of stream");
} }
} catch (IOException e) { } catch (IOException e) {
logException(LOG, WARNING, e); if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
listener.contactExchangeFailed(); listener.contactExchangeFailed();
tryToClose(conn); tryToClose(conn);
return; return;
@@ -223,11 +221,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) {
logException(LOG, WARNING, e); if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
tryToClose(conn); tryToClose(conn);
listener.duplicateContact(remoteInfo.author); listener.duplicateContact(remoteInfo.author);
} catch (DbException e) { } catch (DbException e) {
logException(LOG, WARNING, e); if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
tryToClose(conn); tryToClose(conn);
listener.contactExchangeFailed(); listener.contactExchangeFailed();
} }
@@ -308,7 +306,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) {
logException(LOG, WARNING, e); if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
} }
} }

View File

@@ -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, active); keyManager.addContact(txn, c, master, timestamp, alice);
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;

View File

@@ -32,8 +32,6 @@ 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 {
@@ -129,14 +127,16 @@ 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 start = now(); long now = System.currentTimeMillis();
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();
logDuration(LOG, "Deriving shared secret", start); long duration = System.currentTimeMillis() - now;
if (LOG.isLoggable(INFO))
LOG.info("Deriving shared secret took " + duration + " ms");
return secret; return secret;
} }

View File

@@ -152,47 +152,59 @@ public class MessageEncrypter {
} }
} }
public static void main(String[] args) { public static void main(String[] args) throws Exception {
if (args.length < 1) { if (args.length < 1) {
printUsage(); printUsage();
System.exit(1); return;
} }
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();
System.exit(1); return;
}
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();
System.exit(1); return;
}
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();
System.exit(1); return;
}
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);
} }
} }
@@ -204,46 +216,6 @@ 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();

View File

@@ -10,8 +10,6 @@ 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 {
@@ -52,11 +50,13 @@ 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 = now(); long start = System.currentTimeMillis();
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));
logDuration(LOG, "Deriving key from password", start); long duration = System.currentTimeMillis() - start;
if (LOG.isLoggable(INFO))
LOG.info("Deriving key from password took " + duration + " ms");
return k; return k;
} }
} }

View File

@@ -16,8 +16,7 @@ import java.util.logging.Logger;
import javax.annotation.concurrent.Immutable; import javax.annotation.concurrent.Immutable;
import static org.briarproject.bramble.util.LogUtils.logDuration; import static java.util.logging.Level.INFO;
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
@@ -49,7 +48,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 start = now(); long now = System.currentTimeMillis();
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
@@ -81,14 +80,16 @@ 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);
logDuration(LOG, "Parsing public key", start); long duration = System.currentTimeMillis() - now;
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 start = now(); long now = System.currentTimeMillis();
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
@@ -98,7 +99,9 @@ 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);
logDuration(LOG, "Parsing private key", start); long duration = System.currentTimeMillis() - now;
if (LOG.isLoggable(INFO))
LOG.info("Parsing private key took " + duration + " ms");
return p; return p;
} }
} }

View File

@@ -10,37 +10,37 @@ import java.security.GeneralSecurityException;
interface Signature { interface Signature {
/** /**
* @see java.security.Signature#initSign(java.security.PrivateKey) * @see {@link java.security.Signature#initSign(java.security.PrivateKey)}
*/ */
void initSign(PrivateKey k) throws GeneralSecurityException; void initSign(PrivateKey k) throws GeneralSecurityException;
/** /**
* @see java.security.Signature#initVerify(java.security.PublicKey) * @see {@link java.security.Signature#initVerify(java.security.PublicKey)}
*/ */
void initVerify(PublicKey k) throws GeneralSecurityException; void initVerify(PublicKey k) throws GeneralSecurityException;
/** /**
* @see java.security.Signature#update(byte) * @see {@link java.security.Signature#update(byte)}
*/ */
void update(byte b) throws GeneralSecurityException; void update(byte b) throws GeneralSecurityException;
/** /**
* @see java.security.Signature#update(byte[]) * @see {@link java.security.Signature#update(byte[])}
*/ */
void update(byte[] b) throws GeneralSecurityException; void update(byte[] b) throws GeneralSecurityException;
/** /**
* @see java.security.Signature#update(byte[], int, int) * @see {@link java.security.Signature#update(byte[], int, int)}
*/ */
void update(byte[] b, int off, int len) throws GeneralSecurityException; void update(byte[] b, int off, int len) throws GeneralSecurityException;
/** /**
* @see java.security.Signature#sign()} * @see {@link java.security.Signature#sign()}
*/ */
byte[] sign() throws GeneralSecurityException; byte[] sign() throws GeneralSecurityException;
/** /**
* @see java.security.Signature#verify(byte[]) * @see {@link java.security.Signature#verify(byte[])}
*/ */
boolean verify(byte[] signature) throws GeneralSecurityException; boolean verify(byte[] signature) throws GeneralSecurityException;
} }

View File

@@ -8,7 +8,6 @@ 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
@@ -17,13 +16,11 @@ 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) {
int maxBufferSize) { return new BdfReaderImpl(in, nestedLimit);
return new BdfReaderImpl(in, nestedLimit, maxBufferSize);
} }
} }

View File

@@ -37,16 +37,15 @@ 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, maxBufferSize; private final int nestedLimit;
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, int maxBufferSize) { BdfReaderImpl(InputStream in, int nestedLimit) {
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 {
@@ -92,8 +91,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(); if (hasString()) return readString(Integer.MAX_VALUE);
if (hasRaw()) return readRaw(); if (hasRaw()) return readRaw(Integer.MAX_VALUE);
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();
@@ -246,11 +245,11 @@ class BdfReaderImpl implements BdfReader {
} }
@Override @Override
public String readString() throws IOException { public String readString(int maxLength) 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 > maxBufferSize) throw new FormatException(); if (length < 0 || length > maxLength) 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");
@@ -280,11 +279,11 @@ class BdfReaderImpl implements BdfReader {
} }
@Override @Override
public byte[] readRaw() throws IOException { public byte[] readRaw(int maxLength) 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 > maxBufferSize) throw new FormatException(); if (length < 0 || length > maxLength) 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);
@@ -382,7 +381,7 @@ class BdfReaderImpl implements BdfReader {
BdfDictionary dictionary = new BdfDictionary(); BdfDictionary dictionary = new BdfDictionary();
readDictionaryStart(); readDictionaryStart();
while (!hasDictionaryEnd()) while (!hasDictionaryEnd())
dictionary.put(readString(), readObject(level + 1)); dictionary.put(readString(Integer.MAX_VALUE), readObject(level + 1));
readDictionaryEnd(); readDictionaryEnd();
return dictionary; return dictionary;
} }

View File

@@ -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(); if (reader.hasString()) return reader.readString(Integer.MAX_VALUE);
if (reader.hasRaw()) return reader.readRaw(); if (reader.hasRaw()) return reader.readRaw(Integer.MAX_VALUE);
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();

View File

@@ -34,8 +34,8 @@ import javax.annotation.Nullable;
* A low-level interface to the database (DatabaseComponent provides a * A low-level interface to the database (DatabaseComponent provides a
* high-level interface). Most operations take a transaction argument, which is * high-level interface). Most operations take a transaction argument, which is
* obtained by calling {@link #startTransaction()}. Every transaction must be * obtained by calling {@link #startTransaction()}. Every transaction must be
* terminated by calling either {@link #abortTransaction(Object) abortTransaction(T)} or * terminated by calling either {@link #abortTransaction(T)} or
* {@link #commitTransaction(Object) commitTransaction(T)}, even if an exception is thrown. * {@link #commitTransaction(T)}, even if an exception is thrown.
*/ */
@NotNullByDefault @NotNullByDefault
interface Database<T> { interface Database<T> {
@@ -125,10 +125,16 @@ interface Database<T> {
throws DbException; throws DbException;
/** /**
* Stores the given transport keys for the given contact and returns a * Stores the given transport keys, optionally binding them to the given
* key set ID. * contact, and returns a key set ID.
*/ */
KeySetId addTransportKeys(T txn, ContactId c, TransportKeys k) KeySetId addTransportKeys(T txn, @Nullable 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;
/** /**

View File

@@ -68,15 +68,13 @@ 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
@@ -110,7 +108,7 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
try { try {
close(); close();
} catch (DbException e) { } catch (DbException e) {
logException(LOG, WARNING, e); if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
} }
}); });
return reopened; return reopened;
@@ -127,13 +125,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 = now(); long start = System.currentTimeMillis();
if (readOnly) { if (readOnly) lock.readLock().lock();
lock.readLock().lock(); else lock.writeLock().lock();
logDuration(LOG, "Waiting for read lock", start); if (LOG.isLoggable(FINE)) {
} else { long duration = System.currentTimeMillis() - start;
lock.writeLock().lock(); if (readOnly) LOG.fine("Waited " + duration + " ms for read lock");
logDuration(LOG, "Waiting for write lock", start); else LOG.fine("Waited " + duration + " ms for write lock");
} }
try { try {
return new Transaction(db.startTransaction(), readOnly); return new Transaction(db.startTransaction(), readOnly);
@@ -236,17 +234,29 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
} }
@Override @Override
public KeySetId addTransportKeys(Transaction transaction, ContactId c, public KeySetId addTransportKeys(Transaction transaction,
TransportKeys k) throws DbException { @Nullable ContactId c, TransportKeys 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 (c != null && !db.containsContact(txn, c))
throw new NoSuchContactException(); throw new NoSuchContactException();
if (!db.containsTransport(txn, k.getTransportId())) if (!db.containsTransport(txn, k.getTransportId()))
throw new NoSuchTransportException(); throw new NoSuchTransportException();
return db.addTransportKeys(txn, c, k); 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();
T txn = unbox(transaction);
if (!db.containsContact(txn, c))
throw new NoSuchContactException();
if (!db.containsTransport(txn, t))
throw new NoSuchTransportException();
db.bindTransportKeys(txn, c, t, k);
}
@Override @Override
public boolean containsContact(Transaction transaction, AuthorId remote, public boolean containsContact(Transaction transaction, AuthorId remote,
AuthorId local) throws DbException { AuthorId local) throws DbException {

View File

@@ -53,7 +53,6 @@ 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;
@@ -66,7 +65,6 @@ 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
@@ -76,7 +74,7 @@ import static org.briarproject.bramble.util.LogUtils.logException;
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 = 39; static final int CODE_SCHEMA_VERSION = 38;
// 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;
@@ -238,7 +236,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 NOT NULL," + " contactId INT," // Null if keys are not bound
+ " tagKey _SECRET NOT NULL," + " tagKey _SECRET NOT NULL,"
+ " headerKey _SECRET NOT NULL," + " headerKey _SECRET NOT NULL,"
+ " stream BIGINT NOT NULL," + " stream BIGINT NOT NULL,"
@@ -257,7 +255,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 NOT NULL," + " contactId INT," // Null if keys are not bound
+ " tagKey _SECRET NOT NULL," + " tagKey _SECRET NOT NULL,"
+ " headerKey _SECRET NOT NULL," + " headerKey _SECRET NOT NULL,"
+ " base BIGINT NOT NULL," + " base BIGINT NOT NULL,"
@@ -391,7 +389,7 @@ abstract class JdbcDatabase implements Database<Connection> {
// Package access for testing // Package access for testing
List<Migration<Connection>> getMigrations() { List<Migration<Connection>> getMigrations() {
return singletonList(new Migration38_39()); return Collections.emptyList();
} }
private void storeSchemaVersion(Connection txn, int version) private void storeSchemaVersion(Connection txn, int version)
@@ -405,7 +403,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) {
logException(LOG, WARNING, e); if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
} }
} }
@@ -413,7 +411,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) {
logException(LOG, WARNING, e); if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
} }
} }
@@ -510,11 +508,12 @@ abstract class JdbcDatabase implements Database<Connection> {
} }
} catch (SQLException e) { } catch (SQLException e) {
// Try to close the connection // Try to close the connection
logException(LOG, WARNING, e); if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
try { try {
txn.close(); txn.close();
} catch (SQLException e1) { } catch (SQLException e1) {
logException(LOG, WARNING, e1); if (LOG.isLoggable(WARNING))
LOG.log(WARNING, e1.toString(), e1);
} }
// Whatever happens, allow the database to close // Whatever happens, allow the database to close
connectionsLock.lock(); connectionsLock.lock();
@@ -884,7 +883,7 @@ abstract class JdbcDatabase implements Database<Connection> {
} }
@Override @Override
public KeySetId addTransportKeys(Connection txn, ContactId c, public KeySetId addTransportKeys(Connection txn, @Nullable ContactId c,
TransportKeys k) throws DbException { TransportKeys k) throws DbException {
PreparedStatement ps = null; PreparedStatement ps = null;
ResultSet rs = null; ResultSet rs = null;
@@ -894,7 +893,8 @@ 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);
ps.setInt(1, c.getInt()); if (c == null) ps.setNull(1, INTEGER);
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,7 +922,8 @@ 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());
ps.setInt(2, c.getInt()); if (c == null) ps.setNull(2, INTEGER);
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();
@@ -964,6 +965,33 @@ 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 {
@@ -2144,6 +2172,7 @@ 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));

View File

@@ -1,55 +0,0 @@
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);
}
}
}

View File

@@ -31,7 +31,6 @@ 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 {
@@ -135,7 +134,7 @@ class KeyAgreementConnector {
Thread.currentThread().interrupt(); Thread.currentThread().interrupt();
return null; return null;
} catch (IOException e) { } catch (IOException e) {
logException(LOG, WARNING, e); if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
return null; return null;
} finally { } finally {
stopListening(); stopListening();

View File

@@ -28,7 +28,6 @@ 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
@@ -121,11 +120,13 @@ 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) {
logException(LOG, WARNING, e); if (LOG.isLoggable(WARNING))
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) {
logException(LOG, WARNING, e); if (LOG.isLoggable(WARNING))
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());
} }

View File

@@ -20,7 +20,6 @@ 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.
@@ -73,7 +72,7 @@ class KeyAgreementTransport {
try { try {
writeRecord(ABORT, new byte[0]); writeRecord(ABORT, new byte[0]);
} catch (IOException e) { } catch (IOException e) {
logException(LOG, WARNING, e); if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
exception = true; exception = true;
} }
tryToClose(exception); tryToClose(exception);
@@ -84,7 +83,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) {
logException(LOG, WARNING, e); if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
} }
} }

View File

@@ -30,7 +30,6 @@ 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;
@@ -44,9 +43,6 @@ 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
@@ -105,20 +101,24 @@ class LifecycleManagerImpl implements LifecycleManager, MigrationListener {
} }
private LocalAuthor createLocalAuthor(String nickname) { private LocalAuthor createLocalAuthor(String nickname) {
long start = now(); long now = System.currentTimeMillis();
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);
logDuration(LOG, "Creating local author", start); long duration = System.currentTimeMillis() - now;
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 start = now(); long now = System.currentTimeMillis();
identityManager.registerLocalAuthor(author); identityManager.registerLocalAuthor(author);
logDuration(LOG, "Registering local author", start); long duration = System.currentTimeMillis() - now;
if (LOG.isLoggable(INFO))
LOG.info("Registering local author took " + duration + " ms");
} }
@Override @Override
@@ -129,11 +129,15 @@ class LifecycleManagerImpl implements LifecycleManager, MigrationListener {
} }
try { try {
LOG.info("Starting services"); LOG.info("Starting services");
long start = now(); long start = System.currentTimeMillis();
boolean reopened = db.open(this); boolean reopened = db.open(this);
if (reopened) logDuration(LOG, "Reopening database", start); long duration = System.currentTimeMillis() - start;
else logDuration(LOG, "Creating database", start); if (LOG.isLoggable(INFO)) {
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));
@@ -146,11 +150,13 @@ 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 = now(); start = System.currentTimeMillis();
c.createLocalState(txn); c.createLocalState(txn);
if (LOG.isLoggable(FINE)) { duration = System.currentTimeMillis() - start;
logDuration(LOG, "Starting client " if (LOG.isLoggable(INFO)) {
+ c.getClass().getSimpleName(), start); LOG.info("Starting client "
+ c.getClass().getSimpleName()
+ " took " + duration + " ms");
} }
} }
db.commitTransaction(txn); db.commitTransaction(txn);
@@ -158,11 +164,12 @@ class LifecycleManagerImpl implements LifecycleManager, MigrationListener {
db.endTransaction(txn); db.endTransaction(txn);
} }
for (Service s : services) { for (Service s : services) {
start = now(); start = System.currentTimeMillis();
s.startService(); s.startService();
if (LOG.isLoggable(FINE)) { duration = System.currentTimeMillis() - start;
logDuration(LOG, "Starting service " if (LOG.isLoggable(INFO)) {
+ s.getClass().getSimpleName(), start); LOG.info("Starting service " + s.getClass().getSimpleName()
+ " took " + duration + " ms");
} }
} }
@@ -171,16 +178,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) {
logException(LOG, WARNING, e); if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
return DATA_TOO_OLD_ERROR; return DATA_TOO_OLD_ERROR;
} catch (DataTooNewException e) { } catch (DataTooNewException e) {
logException(LOG, WARNING, e); if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
return DATA_TOO_NEW_ERROR; return DATA_TOO_NEW_ERROR;
} catch (DbException e) { } catch (DbException e) {
logException(LOG, WARNING, e); if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
return DB_ERROR; return DB_ERROR;
} catch (ServiceException e) { } catch (ServiceException e) {
logException(LOG, WARNING, e); if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
return SERVICE_ERROR; return SERVICE_ERROR;
} finally { } finally {
startStopSemaphore.release(); startStopSemaphore.release();
@@ -206,26 +213,29 @@ 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 = now(); long start = System.currentTimeMillis();
s.stopService(); s.stopService();
if (LOG.isLoggable(FINE)) { long duration = System.currentTimeMillis() - start;
logDuration(LOG, "Stopping service " if (LOG.isLoggable(INFO)) {
+ s.getClass().getSimpleName(), start); LOG.info("Stopping service " + s.getClass().getSimpleName()
+ " took " + duration + " ms");
} }
} }
for (ExecutorService e : executors) { for (ExecutorService e : executors) {
if (LOG.isLoggable(FINE)) { if (LOG.isLoggable(INFO)) {
LOG.fine("Stopping executor " LOG.info("Stopping executor "
+ e.getClass().getSimpleName()); + e.getClass().getSimpleName());
} }
e.shutdownNow(); e.shutdownNow();
} }
long start = now(); long start = System.currentTimeMillis();
db.close(); db.close();
logDuration(LOG, "Closing database", start); long duration = System.currentTimeMillis() - start;
if (LOG.isLoggable(INFO))
LOG.info("Closing database took " + duration + " ms");
shutdownLatch.countDown(); shutdownLatch.countDown();
} catch (DbException | ServiceException e) { } catch (DbException | ServiceException e) {
logException(LOG, WARNING, e); if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
} finally { } finally {
startStopSemaphore.release(); startStopSemaphore.release();
} }

View File

@@ -14,12 +14,12 @@ import org.briarproject.bramble.api.sync.SyncSessionFactory;
import org.briarproject.bramble.api.transport.KeyManager; import org.briarproject.bramble.api.transport.KeyManager;
import org.briarproject.bramble.api.transport.StreamContext; import org.briarproject.bramble.api.transport.StreamContext;
import org.briarproject.bramble.api.transport.StreamReaderFactory; import org.briarproject.bramble.api.transport.StreamReaderFactory;
import org.briarproject.bramble.api.transport.StreamWriter;
import org.briarproject.bramble.api.transport.StreamWriterFactory; import org.briarproject.bramble.api.transport.StreamWriterFactory;
import java.io.EOFException; import java.io.EOFException;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
import java.util.logging.Logger; import java.util.logging.Logger;
@@ -27,7 +27,6 @@ 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 {
@@ -102,7 +101,7 @@ class ConnectionManagerImpl implements ConnectionManager {
private SyncSession createSimplexOutgoingSession(StreamContext ctx, private SyncSession createSimplexOutgoingSession(StreamContext ctx,
TransportConnectionWriter w) throws IOException { TransportConnectionWriter w) throws IOException {
StreamWriter streamWriter = streamWriterFactory.createStreamWriter( OutputStream streamWriter = streamWriterFactory.createStreamWriter(
w.getOutputStream(), ctx); w.getOutputStream(), ctx);
return syncSessionFactory.createSimplexOutgoingSession( return syncSessionFactory.createSimplexOutgoingSession(
ctx.getContactId(), w.getMaxLatency(), streamWriter); ctx.getContactId(), w.getMaxLatency(), streamWriter);
@@ -110,7 +109,7 @@ class ConnectionManagerImpl implements ConnectionManager {
private SyncSession createDuplexOutgoingSession(StreamContext ctx, private SyncSession createDuplexOutgoingSession(StreamContext ctx,
TransportConnectionWriter w) throws IOException { TransportConnectionWriter w) throws IOException {
StreamWriter streamWriter = streamWriterFactory.createStreamWriter( OutputStream streamWriter = streamWriterFactory.createStreamWriter(
w.getOutputStream(), ctx); w.getOutputStream(), ctx);
return syncSessionFactory.createDuplexOutgoingSession( return syncSessionFactory.createDuplexOutgoingSession(
ctx.getContactId(), w.getMaxLatency(), w.getMaxIdleTime(), ctx.getContactId(), w.getMaxLatency(), w.getMaxIdleTime(),
@@ -136,7 +135,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) {
logException(LOG, WARNING, e); if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
disposeReader(true, false); disposeReader(true, false);
return; return;
} }
@@ -152,7 +151,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) {
logException(LOG, WARNING, e); if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
disposeReader(true, true); disposeReader(true, true);
} finally { } finally {
connectionRegistry.unregisterConnection(contactId, transportId, connectionRegistry.unregisterConnection(contactId, transportId,
@@ -164,7 +163,7 @@ class ConnectionManagerImpl implements ConnectionManager {
try { try {
reader.dispose(exception, recognised); reader.dispose(exception, recognised);
} catch (IOException e) { } catch (IOException e) {
logException(LOG, WARNING, e); if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
} }
} }
} }
@@ -189,7 +188,7 @@ class ConnectionManagerImpl implements ConnectionManager {
try { try {
ctx = keyManager.getStreamContext(contactId, transportId); ctx = keyManager.getStreamContext(contactId, transportId);
} catch (DbException e) { } catch (DbException e) {
logException(LOG, WARNING, e); if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
disposeWriter(true); disposeWriter(true);
return; return;
} }
@@ -205,7 +204,7 @@ class ConnectionManagerImpl implements ConnectionManager {
createSimplexOutgoingSession(ctx, writer).run(); createSimplexOutgoingSession(ctx, writer).run();
disposeWriter(false); disposeWriter(false);
} catch (IOException e) { } catch (IOException e) {
logException(LOG, WARNING, e); if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
disposeWriter(true); disposeWriter(true);
} finally { } finally {
connectionRegistry.unregisterConnection(contactId, transportId, connectionRegistry.unregisterConnection(contactId, transportId,
@@ -217,7 +216,7 @@ class ConnectionManagerImpl implements ConnectionManager {
try { try {
writer.dispose(exception); writer.dispose(exception);
} catch (IOException e) { } catch (IOException e) {
logException(LOG, WARNING, e); if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
} }
} }
} }
@@ -247,7 +246,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) {
logException(LOG, WARNING, e); if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
disposeReader(true, false); disposeReader(true, false);
return; return;
} }
@@ -266,7 +265,7 @@ class ConnectionManagerImpl implements ConnectionManager {
incomingSession.run(); incomingSession.run();
disposeReader(false, true); disposeReader(false, true);
} catch (IOException e) { } catch (IOException e) {
logException(LOG, WARNING, e); if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
disposeReader(true, true); disposeReader(true, true);
} finally { } finally {
connectionRegistry.unregisterConnection(contactId, transportId, connectionRegistry.unregisterConnection(contactId, transportId,
@@ -280,7 +279,7 @@ class ConnectionManagerImpl implements ConnectionManager {
try { try {
ctx = keyManager.getStreamContext(contactId, transportId); ctx = keyManager.getStreamContext(contactId, transportId);
} catch (DbException e) { } catch (DbException e) {
logException(LOG, WARNING, e); if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
disposeWriter(true); disposeWriter(true);
return; return;
} }
@@ -295,30 +294,28 @@ class ConnectionManagerImpl implements ConnectionManager {
outgoingSession.run(); outgoingSession.run();
disposeWriter(false); disposeWriter(false);
} catch (IOException e) { } catch (IOException e) {
logException(LOG, WARNING, e); if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
disposeWriter(true); disposeWriter(true);
} }
} }
private void disposeReader(boolean exception, boolean recognised) { private void disposeReader(boolean exception, boolean recognised) {
// Interrupt the outgoing session so it finishes cleanly if (exception && outgoingSession != null)
if (outgoingSession != null) outgoingSession.interrupt(); outgoingSession.interrupt();
try { try {
reader.dispose(exception, recognised); reader.dispose(exception, recognised);
} catch (IOException e) { } catch (IOException e) {
logException(LOG, WARNING, e); if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
} }
} }
private void disposeWriter(boolean exception) { private void disposeWriter(boolean exception) {
// Interrupt the incoming session if an exception occurred,
// otherwise wait for the end of stream marker
if (exception && incomingSession != null) if (exception && incomingSession != null)
incomingSession.interrupt(); incomingSession.interrupt();
try { try {
writer.dispose(exception); writer.dispose(exception);
} catch (IOException e) { } catch (IOException e) {
logException(LOG, WARNING, e); if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
} }
} }
} }
@@ -348,7 +345,7 @@ class ConnectionManagerImpl implements ConnectionManager {
try { try {
ctx = keyManager.getStreamContext(contactId, transportId); ctx = keyManager.getStreamContext(contactId, transportId);
} catch (DbException e) { } catch (DbException e) {
logException(LOG, WARNING, e); if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
disposeWriter(true); disposeWriter(true);
return; return;
} }
@@ -365,7 +362,7 @@ class ConnectionManagerImpl implements ConnectionManager {
outgoingSession.run(); outgoingSession.run();
disposeWriter(false); disposeWriter(false);
} catch (IOException e) { } catch (IOException e) {
logException(LOG, WARNING, e); if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
disposeWriter(true); disposeWriter(true);
} }
} }
@@ -377,7 +374,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) {
logException(LOG, WARNING, e); if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
disposeReader(true, false); disposeReader(true, false);
return; return;
} }
@@ -401,7 +398,7 @@ class ConnectionManagerImpl implements ConnectionManager {
incomingSession.run(); incomingSession.run();
disposeReader(false, true); disposeReader(false, true);
} catch (IOException e) { } catch (IOException e) {
logException(LOG, WARNING, e); if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
disposeReader(true, true); disposeReader(true, true);
} finally { } finally {
connectionRegistry.unregisterConnection(contactId, transportId, connectionRegistry.unregisterConnection(contactId, transportId,
@@ -410,24 +407,22 @@ class ConnectionManagerImpl implements ConnectionManager {
} }
private void disposeReader(boolean exception, boolean recognised) { private void disposeReader(boolean exception, boolean recognised) {
// Interrupt the outgoing session so it finishes cleanly if (exception && outgoingSession != null)
if (outgoingSession != null) outgoingSession.interrupt(); outgoingSession.interrupt();
try { try {
reader.dispose(exception, recognised); reader.dispose(exception, recognised);
} catch (IOException e) { } catch (IOException e) {
logException(LOG, WARNING, e); if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
} }
} }
private void disposeWriter(boolean exception) { private void disposeWriter(boolean exception) {
// Interrupt the incoming session if an exception occurred,
// otherwise wait for the end of stream marker
if (exception && incomingSession != null) if (exception && incomingSession != null)
incomingSession.interrupt(); incomingSession.interrupt();
try { try {
writer.dispose(exception); writer.dispose(exception);
} catch (IOException e) { } catch (IOException e) {
logException(LOG, WARNING, e); if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
} }
} }
} }

View File

@@ -106,7 +106,7 @@ class ConnectionRegistryImpl implements ConnectionRegistry {
if (m == null) return Collections.emptyList(); if (m == null) return Collections.emptyList();
List<ContactId> ids = new ArrayList<>(m.keySet()); List<ContactId> ids = new ArrayList<>(m.keySet());
if (LOG.isLoggable(INFO)) if (LOG.isLoggable(INFO))
LOG.info(ids.size() + " contacts connected: " + t); LOG.info(ids.size() + " contacts connected");
return ids; return ids;
} finally { } finally {
lock.unlock(); lock.unlock();

View File

@@ -8,7 +8,6 @@ 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;
@@ -30,31 +29,25 @@ 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.system.Clock; import org.briarproject.bramble.api.ui.UiCallback;
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
@@ -64,15 +57,12 @@ 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 SecureRandom random; private final UiCallback uiCallback;
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;
@@ -80,41 +70,27 @@ 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, PluginManagerImpl(@IoExecutor Executor ioExecutor, EventBus eventBus,
@Scheduler ScheduledExecutorService scheduler, EventBus eventBus,
PluginConfig pluginConfig, ConnectionManager connectionManager, PluginConfig pluginConfig, ConnectionManager connectionManager,
ConnectionRegistry connectionRegistry,
SettingsManager settingsManager, SettingsManager settingsManager,
TransportPropertyManager transportPropertyManager, TransportPropertyManager transportPropertyManager,
SecureRandom random, Clock clock) { UiCallback uiCallback) {
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.random = random; this.uiCallback = uiCallback;
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() { public void startService() throws ServiceException {
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()) {
@@ -209,16 +185,17 @@ class PluginManagerImpl implements PluginManager, Service {
@Override @Override
public void run() { public void run() {
try { try {
long start = now(); long start = System.currentTimeMillis();
plugin.start(); plugin.start();
if (LOG.isLoggable(FINE)) { long duration = System.currentTimeMillis() - start;
logDuration(LOG, "Starting plugin " + plugin.getId(), if (LOG.isLoggable(INFO)) {
start); LOG.info("Starting plugin " + plugin.getId() + " took " +
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");
logException(LOG, WARNING, e); LOG.log(WARNING, e.toString(), e);
} }
} finally { } finally {
startLatch.countDown(); startLatch.countDown();
@@ -246,11 +223,12 @@ 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 = now(); long start = System.currentTimeMillis();
plugin.stop(); plugin.stop();
if (LOG.isLoggable(FINE)) { long duration = System.currentTimeMillis() - start;
logDuration(LOG, "Stopping plugin " + plugin.getId(), if (LOG.isLoggable(INFO)) {
start); LOG.info("Stopping plugin " + plugin.getId()
+ " 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");
@@ -258,7 +236,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");
logException(LOG, WARNING, e); LOG.log(WARNING, e.toString(), e);
} }
} finally { } finally {
stopLatch.countDown(); stopLatch.countDown();
@@ -280,7 +258,7 @@ class PluginManagerImpl implements PluginManager, Service {
try { try {
return settingsManager.getSettings(id.getString()); return settingsManager.getSettings(id.getString());
} catch (DbException e) { } catch (DbException e) {
logException(LOG, WARNING, e); if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
return new Settings(); return new Settings();
} }
} }
@@ -290,7 +268,27 @@ class PluginManagerImpl implements PluginManager, Service {
try { try {
return transportPropertyManager.getLocalProperties(id); return transportPropertyManager.getLocalProperties(id);
} catch (DbException e) { } catch (DbException e) {
logException(LOG, WARNING, e); if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), 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();
} }
} }
@@ -300,7 +298,7 @@ class PluginManagerImpl implements PluginManager, Service {
try { try {
settingsManager.mergeSettings(s, id.getString()); settingsManager.mergeSettings(s, id.getString());
} catch (DbException e) { } catch (DbException e) {
logException(LOG, WARNING, e); if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
} }
} }
@@ -309,10 +307,25 @@ class PluginManagerImpl implements PluginManager, Service {
try { try {
transportPropertyManager.mergeLocalProperties(id, p); transportPropertyManager.mergeLocalProperties(id, p);
} catch (DbException e) { } catch (DbException e) {
logException(LOG, WARNING, e); if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), 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));

View File

@@ -1,10 +1,18 @@
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;
@@ -18,6 +26,8 @@ public class PluginModule {
public static class EagerSingletons { public static class EagerSingletons {
@Inject @Inject
PluginManager pluginManager; PluginManager pluginManager;
@Inject
Poller poller;
} }
@Provides @Provides
@@ -25,6 +35,19 @@ 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(

View File

@@ -2,7 +2,6 @@ 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;
@@ -20,15 +19,14 @@ 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.HashSet;
import java.util.Map; import java.util.Map;
import java.util.Set;
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;
@@ -37,11 +35,10 @@ 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
@@ -54,38 +51,40 @@ 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
private final Set<TransportId> polling; // 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();
tasks = new HashMap<>(); tasks = new HashMap<>();
polling = new HashSet<>();
} }
@Override @Override
public void eventOccurred(Event e) { public void eventOccurred(Event e) {
if (e instanceof ContactStatusChangedEvent) { if (e instanceof ContactStatusChangedEvent) {
ContactStatusChangedEvent c = (ContactStatusChangedEvent) e; ContactStatusChangedEvent c = (ContactStatusChangedEvent) e;
/*
if (c.isActive()) { if (c.isActive()) {
// Connect to the newly activated contact // Connect to the newly activated contact
connectToContact(c.getContactId()); connectToContact(c.getContactId());
} }
*/
} else if (e instanceof ConnectionClosedEvent) { } else if (e instanceof ConnectionClosedEvent) {
ConnectionClosedEvent c = (ConnectionClosedEvent) e; ConnectionClosedEvent c = (ConnectionClosedEvent) e;
// Reschedule polling, the polling interval may have decreased // Reschedule polling, the polling interval may have decreased
@@ -127,15 +126,10 @@ 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)) return; if (!connectionRegistry.isConnected(c, t)) {
try { TransportConnectionWriter w = p.createWriter(c);
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);
} }
}); });
} }
@@ -143,15 +137,10 @@ 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)) return; if (!connectionRegistry.isConnected(c, t)) {
try { DuplexTransportConnection d = p.createConnection(c);
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);
} }
}); });
} }
@@ -203,17 +192,7 @@ 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);
try { p.poll(connectionRegistry.getConnectedContacts(t));
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 {
@@ -242,20 +221,33 @@ class Poller implements EventListener {
@Override @Override
@IoExecutor @IoExecutor
public void run() { public void run() {
TransportId t = plugin.getId();
boolean shouldPoll;
lock.lock(); lock.lock();
try { try {
TransportId t = plugin.getId();
ScheduledPollTask scheduled = tasks.get(t); ScheduledPollTask scheduled = tasks.get(t);
if (scheduled != null && scheduled.task != this) if (scheduled != null && scheduled.task != this)
return; // Replaced by another task return; // Replaced by another task
tasks.remove(t); tasks.remove(t);
// Don't poll again if last poll is still running
shouldPoll = polling.add(t);
} finally { } finally {
lock.unlock(); lock.unlock();
} }
int delay = plugin.getPollingInterval(); int delay = plugin.getPollingInterval();
if (randomiseNext) delay = (int) (delay * random.nextDouble()); if (randomiseNext) delay = (int) (delay * random.nextDouble());
schedule(plugin, delay, false); schedule(plugin, delay, false);
poll(plugin); if (shouldPoll) {
poll(plugin);
} else if (LOG.isLoggable(INFO)) {
LOG.info("Last poll for " + t + " is still running");
}
lock.lock();
try {
polling.remove(t);
} finally {
lock.unlock();
}
} }
} }
} }

View File

@@ -13,7 +13,6 @@ 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
@@ -93,7 +92,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) {
logException(LOG, WARNING, e); if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
} }
} }

View File

@@ -26,8 +26,11 @@ 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.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
@@ -43,7 +46,6 @@ 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
@@ -53,6 +55,12 @@ abstract class BluetoothPlugin<SS> implements DuplexPlugin, EventListener {
private static final Logger LOG = private static final Logger LOG =
Logger.getLogger(BluetoothPlugin.class.getName()); Logger.getLogger(BluetoothPlugin.class.getName());
/**
* How many milliseconds to pause between connection attempts when
* polling, to avoid interfering with other Bluetooth or wifi connections.
*/
private static final int POLLING_PAUSE_MS = 3000;
final BluetoothConnectionLimiter connectionLimiter; final BluetoothConnectionLimiter connectionLimiter;
private final Executor ioExecutor; private final Executor ioExecutor;
@@ -170,7 +178,7 @@ abstract class BluetoothPlugin<SS> implements DuplexPlugin, EventListener {
try { try {
ss = openServerSocket(contactConnectionsUuid); ss = openServerSocket(contactConnectionsUuid);
} catch (IOException e) { } catch (IOException e) {
logException(LOG, WARNING, e); if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
return; return;
} }
if (!isRunning() || !shouldAllowContactConnections()) { if (!isRunning() || !shouldAllowContactConnections()) {
@@ -250,27 +258,45 @@ abstract class BluetoothPlugin<SS> implements DuplexPlugin, EventListener {
} }
@Override @Override
public void poll(Map<ContactId, TransportProperties> contacts) { public void poll(Collection<ContactId> connected) {
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 a random order
for (Entry<ContactId, TransportProperties> e : contacts.entrySet()) { Map<ContactId, TransportProperties> remote =
String address = e.getValue().get(PROP_ADDRESS); callback.getRemoteProperties();
if (StringUtils.isNullOrEmpty(address)) continue; List<ContactId> keys = new ArrayList<>(remote.keySet());
String uuid = e.getValue().get(PROP_UUID); Collections.shuffle(keys);
if (StringUtils.isNullOrEmpty(uuid)) continue; ioExecutor.execute(() -> {
ContactId c = e.getKey(); boolean first = true;
ioExecutor.execute(() -> { for (ContactId c : keys) {
if (!isRunning() || !shouldAllowContactConnections()) return; if (!isRunning() || !shouldAllowContactConnections()) return;
if (!connectionLimiter.canOpenContactConnection()) return; if (!connectionLimiter.canOpenContactConnection()) return;
if (connected.contains(c)) continue;
TransportProperties p = remote.get(c);
String address = p.get(PROP_ADDRESS);
if (StringUtils.isNullOrEmpty(address)) continue;
String uuid = p.get(PROP_UUID);
if (StringUtils.isNullOrEmpty(uuid)) continue;
// Pause between connection attempts
if (first) {
first = false;
} else {
try {
Thread.sleep(POLLING_PAUSE_MS);
} catch (InterruptedException ex) {
LOG.info("Interrupted while polling");
Thread.currentThread().interrupt();
return;
}
}
DuplexTransportConnection conn = connect(address, uuid); DuplexTransportConnection conn = connect(address, uuid);
if (conn != null) { if (conn != null) {
backoff.reset(); backoff.reset();
if (connectionLimiter.contactConnectionOpened(conn)) if (connectionLimiter.contactConnectionOpened(conn))
callback.outgoingConnectionCreated(c, conn); callback.outgoingConnectionCreated(c, conn);
} }
}); }
} });
} }
@Nullable @Nullable
@@ -305,9 +331,10 @@ abstract class BluetoothPlugin<SS> implements DuplexPlugin, EventListener {
} }
@Override @Override
public DuplexTransportConnection createConnection(TransportProperties p) { public DuplexTransportConnection createConnection(ContactId c) {
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);
@@ -337,7 +364,7 @@ abstract class BluetoothPlugin<SS> implements DuplexPlugin, EventListener {
try { try {
ss = openServerSocket(uuid); ss = openServerSocket(uuid);
} catch (IOException e) { } catch (IOException e) {
logException(LOG, WARNING, e); if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
return null; return null;
} }
if (!isRunning()) { if (!isRunning()) {

View File

@@ -1,22 +1,27 @@
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.plugin.FileConstants.PROP_PATH; import static org.briarproject.bramble.api.transport.TransportConstants.MIN_STREAM_LENGTH;
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 {
@@ -24,15 +29,25 @@ 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 abstract void writerFinished(File f, boolean exception); protected volatile boolean running = false;
protected abstract void readerFinished(File f, boolean exception, @Nullable
boolean recognised); protected abstract File chooseOutputDirectory();
FilePlugin(SimplexPluginCallback callback, int maxLatency) { protected abstract Collection<File> findFilesByName(String filename);
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;
} }
@@ -43,36 +58,81 @@ abstract class FilePlugin implements SimplexPlugin {
} }
@Override @Override
public TransportConnectionReader createReader(TransportProperties p) { public int getMaxIdleTime() {
if (!isRunning()) return null; return Integer.MAX_VALUE; // We don't need keepalives
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 {
File file = new File(path); long capacity = dir.getFreeSpace();
FileInputStream in = new FileInputStream(file); if (capacity < MIN_STREAM_LENGTH) return null;
return new FileTransportReader(file, in, this); OutputStream out = new FileOutputStream(f);
return new FileTransportWriter(f, out, capacity, this);
} catch (IOException e) { } catch (IOException e) {
logException(LOG, WARNING, e); if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
f.delete();
return null; return null;
} }
} }
@Override protected void createReaderFromFile(File f) {
public TransportConnectionWriter createWriter(TransportProperties p) { if (!running) return;
if (!isRunning()) return null; ioExecutor.execute(new ReaderCreator(f));
String path = p.get(PROP_PATH); }
if (isNullOrEmpty(path)) return null;
try { private class ReaderCreator implements Runnable {
File file = new File(path);
if (!file.exists() && !file.createNewFile()) { private final File file;
LOG.info("Failed to create file");
return null; private ReaderCreator(File file) {
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;
} }
} }
} }

View File

@@ -9,7 +9,6 @@ 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 {
@@ -37,8 +36,11 @@ class FileTransportReader implements TransportConnectionReader {
try { try {
in.close(); in.close();
} catch (IOException e) { } catch (IOException e) {
logException(LOG, WARNING, e); if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
}
if (recognised) {
file.delete();
plugin.readerFinished(file);
} }
plugin.readerFinished(file, exception, recognised);
} }
} }

View File

@@ -9,7 +9,6 @@ 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 {
@@ -19,11 +18,14 @@ 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, FilePlugin plugin) { FileTransportWriter(File file, OutputStream out, long capacity,
FilePlugin plugin) {
this.file = file; this.file = file;
this.out = out; this.out = out;
this.capacity = capacity;
this.plugin = plugin; this.plugin = plugin;
} }
@@ -37,6 +39,11 @@ 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;
@@ -47,8 +54,9 @@ class FileTransportWriter implements TransportConnectionWriter {
try { try {
out.close(); out.close();
} catch (IOException e) { } catch (IOException e) {
logException(LOG, WARNING, e); if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
} }
plugin.writerFinished(file, exception); if (exception) file.delete();
else plugin.writerFinished(file);
} }
} }

View File

@@ -35,7 +35,6 @@ 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
@@ -296,7 +295,7 @@ class LanTcpPlugin extends TcpPlugin {
try { try {
ss.close(); ss.close();
} catch (IOException e) { } catch (IOException e) {
logException(LOG, WARNING, e); if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
} }
} }
} }

View File

@@ -17,7 +17,6 @@ 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
@@ -60,7 +59,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) {
logException(LOG, WARNING, e); if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
} }
return new MappingResult(internal, external, port, succeeded); return new MappingResult(internal, external, port, succeeded);
} }
@@ -77,7 +76,7 @@ class PortMapperImpl implements PortMapper {
try { try {
d.discover(); d.discover();
} catch (IOException | SAXException | ParserConfigurationException e) { } catch (IOException | SAXException | ParserConfigurationException e) {
logException(LOG, WARNING, e); if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
} }
gateway = d.getValidGateway(); gateway = d.getValidGateway();
} }
@@ -88,7 +87,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) {
logException(LOG, WARNING, e); if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
} }
} }
} }

View File

@@ -37,7 +37,6 @@ 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
@@ -153,7 +152,7 @@ abstract class TcpPlugin implements DuplexPlugin {
try { try {
if (ss != null) ss.close(); if (ss != null) ss.close();
} catch (IOException e) { } catch (IOException e) {
logException(LOG, WARNING, e); if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
} finally { } finally {
callback.transportDisabled(); callback.transportDisabled();
} }
@@ -208,16 +207,20 @@ abstract class TcpPlugin implements DuplexPlugin {
} }
@Override @Override
public void poll(Map<ContactId, TransportProperties> contacts) { public void poll(Collection<ContactId> connected) {
if (!isRunning()) return; if (!isRunning()) return;
backoff.increment(); backoff.increment();
for (Entry<ContactId, TransportProperties> e : contacts.entrySet()) { Map<ContactId, TransportProperties> remote =
connectAndCallBack(e.getKey(), e.getValue()); callback.getRemoteProperties();
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();
@@ -227,8 +230,13 @@ abstract class TcpPlugin implements DuplexPlugin {
} }
@Override @Override
public DuplexTransportConnection createConnection(TransportProperties p) { public DuplexTransportConnection createConnection(ContactId c) {
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)) {
@@ -307,7 +315,7 @@ abstract class TcpPlugin implements DuplexPlugin {
try { try {
ifaces = Collections.list(NetworkInterface.getNetworkInterfaces()); ifaces = Collections.list(NetworkInterface.getNetworkInterfaces());
} catch (SocketException e) { } catch (SocketException e) {
logException(LOG, WARNING, e); if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
return Collections.emptyList(); return Collections.emptyList();
} }
List<InetAddress> addrs = new ArrayList<>(); List<InetAddress> addrs = new ArrayList<>();

View File

@@ -16,7 +16,6 @@ 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
@@ -79,7 +78,7 @@ class ReliabilityLayerImpl implements ReliabilityLayer, WriteHandler {
Thread.currentThread().interrupt(); Thread.currentThread().interrupt();
running = false; running = false;
} catch (IOException e) { } catch (IOException e) {
logException(LOG, WARNING, e); if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
running = false; running = false;
} }
}); });

View File

@@ -1,12 +1,7 @@
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;
@@ -23,20 +18,17 @@ 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, EventListener { class DevReporterImpl implements DevReporter {
private static final Logger LOG = private static final Logger LOG =
Logger.getLogger(DevReporterImpl.class.getName()); Logger.getLogger(DevReporterImpl.class.getName());
@@ -44,15 +36,12 @@ class DevReporterImpl implements DevReporter, EventListener {
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;
@Inject DevReporterImpl(CryptoComponent crypto, DevConfig devConfig,
DevReporterImpl(@IoExecutor Executor ioExecutor, CryptoComponent crypto, SocketFactory torSocketFactory) {
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;
@@ -74,7 +63,6 @@ class DevReporterImpl implements DevReporter, EventListener {
@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);
@@ -94,17 +82,7 @@ class DevReporterImpl implements DevReporter, EventListener {
} }
@Override @Override
public void eventOccurred(Event e) { public void sendReports(File reportDir) {
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
@@ -133,7 +111,7 @@ class DevReporterImpl implements DevReporter, EventListener {
try { try {
if (c != null) c.close(); if (c != null) c.close();
} catch (IOException e) { } catch (IOException e) {
logException(LOG, WARNING, e); if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
} }
} }
@@ -141,7 +119,7 @@ class DevReporterImpl implements DevReporter, EventListener {
try { try {
if (s != null) s.close(); if (s != null) s.close();
} catch (IOException e) { } catch (IOException e) {
logException(LOG, WARNING, e); if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
} }
} }
} }

View File

@@ -1,10 +1,10 @@
package org.briarproject.bramble.reporting; package org.briarproject.bramble.reporting;
import org.briarproject.bramble.api.event.EventBus; import org.briarproject.bramble.api.crypto.CryptoComponent;
import org.briarproject.bramble.api.reporting.DevConfig;
import org.briarproject.bramble.api.reporting.DevReporter; import org.briarproject.bramble.api.reporting.DevReporter;
import javax.inject.Inject; import javax.net.SocketFactory;
import javax.inject.Singleton;
import dagger.Module; import dagger.Module;
import dagger.Provides; import dagger.Provides;
@@ -12,16 +12,9 @@ import dagger.Provides;
@Module @Module
public class ReportingModule { public class ReportingModule {
public static class EagerSingletons {
@Inject
DevReporter devReporter;
}
@Provides @Provides
@Singleton DevReporter provideDevReporter(CryptoComponent crypto,
DevReporter provideDevReporter(DevReporterImpl devReporter, DevConfig devConfig, SocketFactory torSocketFactory) {
EventBus eventBus) { return new DevReporterImpl(crypto, devConfig, torSocketFactory);
eventBus.addListener(devReporter);
return devReporter;
} }
} }

View File

@@ -23,7 +23,6 @@ import org.briarproject.bramble.api.sync.event.MessageSharedEvent;
import org.briarproject.bramble.api.sync.event.MessageToAckEvent; import org.briarproject.bramble.api.sync.event.MessageToAckEvent;
import org.briarproject.bramble.api.sync.event.MessageToRequestEvent; import org.briarproject.bramble.api.sync.event.MessageToRequestEvent;
import org.briarproject.bramble.api.system.Clock; import org.briarproject.bramble.api.system.Clock;
import org.briarproject.bramble.api.transport.StreamWriter;
import java.io.IOException; import java.io.IOException;
import java.util.Collection; import java.util.Collection;
@@ -42,7 +41,6 @@ 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
@@ -69,7 +67,6 @@ class DuplexOutgoingSession implements SyncSession, EventListener {
private final Clock clock; private final Clock clock;
private final ContactId contactId; private final ContactId contactId;
private final int maxLatency, maxIdleTime; private final int maxLatency, maxIdleTime;
private final StreamWriter streamWriter;
private final SyncRecordWriter recordWriter; private final SyncRecordWriter recordWriter;
private final BlockingQueue<ThrowingRunnable<IOException>> writerTasks; private final BlockingQueue<ThrowingRunnable<IOException>> writerTasks;
@@ -84,8 +81,7 @@ class DuplexOutgoingSession implements SyncSession, EventListener {
DuplexOutgoingSession(DatabaseComponent db, Executor dbExecutor, DuplexOutgoingSession(DatabaseComponent db, Executor dbExecutor,
EventBus eventBus, Clock clock, ContactId contactId, int maxLatency, EventBus eventBus, Clock clock, ContactId contactId, int maxLatency,
int maxIdleTime, StreamWriter streamWriter, int maxIdleTime, SyncRecordWriter recordWriter) {
SyncRecordWriter recordWriter) {
this.db = db; this.db = db;
this.dbExecutor = dbExecutor; this.dbExecutor = dbExecutor;
this.eventBus = eventBus; this.eventBus = eventBus;
@@ -93,7 +89,6 @@ class DuplexOutgoingSession implements SyncSession, EventListener {
this.contactId = contactId; this.contactId = contactId;
this.maxLatency = maxLatency; this.maxLatency = maxLatency;
this.maxIdleTime = maxIdleTime; this.maxIdleTime = maxIdleTime;
this.streamWriter = streamWriter;
this.recordWriter = recordWriter; this.recordWriter = recordWriter;
writerTasks = new LinkedBlockingQueue<>(); writerTasks = new LinkedBlockingQueue<>();
} }
@@ -154,7 +149,7 @@ class DuplexOutgoingSession implements SyncSession, EventListener {
dataToFlush = true; dataToFlush = true;
} }
} }
streamWriter.sendEndOfStream(); if (dataToFlush) recordWriter.flush();
} catch (InterruptedException e) { } catch (InterruptedException e) {
LOG.info("Interrupted while waiting for a record to write"); LOG.info("Interrupted while waiting for a record to write");
Thread.currentThread().interrupt(); Thread.currentThread().interrupt();
@@ -241,7 +236,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) {
logException(LOG, WARNING, e); if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
interrupt(); interrupt();
} }
} }
@@ -288,7 +283,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) {
logException(LOG, WARNING, e); if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
interrupt(); interrupt();
} }
} }
@@ -335,7 +330,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) {
logException(LOG, WARNING, e); if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
interrupt(); interrupt();
} }
} }
@@ -380,7 +375,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) {
logException(LOG, WARNING, e); if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
interrupt(); interrupt();
} }
} }

View File

@@ -28,7 +28,6 @@ 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}.
@@ -64,11 +63,7 @@ class IncomingSession implements SyncSession, EventListener {
eventBus.addListener(this); eventBus.addListener(this);
try { try {
// Read records until interrupted or EOF // Read records until interrupted or EOF
while (!interrupted) { while (!interrupted && !recordReader.eof()) {
if (recordReader.eof()) {
LOG.info("End of stream");
return;
}
if (recordReader.hasAck()) { if (recordReader.hasAck()) {
Ack a = recordReader.readAck(); Ack a = recordReader.readAck();
dbExecutor.execute(new ReceiveAck(a)); dbExecutor.execute(new ReceiveAck(a));
@@ -128,7 +123,7 @@ class IncomingSession implements SyncSession, EventListener {
db.endTransaction(txn); db.endTransaction(txn);
} }
} catch (DbException e) { } catch (DbException e) {
logException(LOG, WARNING, e); if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
interrupt(); interrupt();
} }
} }
@@ -154,7 +149,7 @@ class IncomingSession implements SyncSession, EventListener {
db.endTransaction(txn); db.endTransaction(txn);
} }
} catch (DbException e) { } catch (DbException e) {
logException(LOG, WARNING, e); if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
interrupt(); interrupt();
} }
} }
@@ -180,7 +175,7 @@ class IncomingSession implements SyncSession, EventListener {
db.endTransaction(txn); db.endTransaction(txn);
} }
} catch (DbException e) { } catch (DbException e) {
logException(LOG, WARNING, e); if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
interrupt(); interrupt();
} }
} }
@@ -206,7 +201,7 @@ class IncomingSession implements SyncSession, EventListener {
db.endTransaction(txn); db.endTransaction(txn);
} }
} catch (DbException e) { } catch (DbException e) {
logException(LOG, WARNING, e); if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
interrupt(); interrupt();
} }
} }

View File

@@ -15,7 +15,6 @@ import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.sync.Ack; import org.briarproject.bramble.api.sync.Ack;
import org.briarproject.bramble.api.sync.SyncRecordWriter; import org.briarproject.bramble.api.sync.SyncRecordWriter;
import org.briarproject.bramble.api.sync.SyncSession; import org.briarproject.bramble.api.sync.SyncSession;
import org.briarproject.bramble.api.transport.StreamWriter;
import java.io.IOException; import java.io.IOException;
import java.util.Collection; import java.util.Collection;
@@ -32,7 +31,6 @@ 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
@@ -53,7 +51,6 @@ class SimplexOutgoingSession implements SyncSession, EventListener {
private final EventBus eventBus; private final EventBus eventBus;
private final ContactId contactId; private final ContactId contactId;
private final int maxLatency; private final int maxLatency;
private final StreamWriter streamWriter;
private final SyncRecordWriter recordWriter; private final SyncRecordWriter recordWriter;
private final AtomicInteger outstandingQueries; private final AtomicInteger outstandingQueries;
private final BlockingQueue<ThrowingRunnable<IOException>> writerTasks; private final BlockingQueue<ThrowingRunnable<IOException>> writerTasks;
@@ -61,14 +58,13 @@ class SimplexOutgoingSession implements SyncSession, EventListener {
private volatile boolean interrupted = false; private volatile boolean interrupted = false;
SimplexOutgoingSession(DatabaseComponent db, Executor dbExecutor, SimplexOutgoingSession(DatabaseComponent db, Executor dbExecutor,
EventBus eventBus, ContactId contactId, int maxLatency, EventBus eventBus, ContactId contactId,
StreamWriter streamWriter, SyncRecordWriter recordWriter) { int maxLatency, SyncRecordWriter recordWriter) {
this.db = db; this.db = db;
this.dbExecutor = dbExecutor; this.dbExecutor = dbExecutor;
this.eventBus = eventBus; this.eventBus = eventBus;
this.contactId = contactId; this.contactId = contactId;
this.maxLatency = maxLatency; this.maxLatency = maxLatency;
this.streamWriter = streamWriter;
this.recordWriter = recordWriter; this.recordWriter = recordWriter;
outstandingQueries = new AtomicInteger(2); // One per type of record outstandingQueries = new AtomicInteger(2); // One per type of record
writerTasks = new LinkedBlockingQueue<>(); writerTasks = new LinkedBlockingQueue<>();
@@ -89,7 +85,7 @@ class SimplexOutgoingSession implements SyncSession, EventListener {
if (task == CLOSE) break; if (task == CLOSE) break;
task.run(); task.run();
} }
streamWriter.sendEndOfStream(); recordWriter.flush();
} catch (InterruptedException e) { } catch (InterruptedException e) {
LOG.info("Interrupted while waiting for a record to write"); LOG.info("Interrupted while waiting for a record to write");
Thread.currentThread().interrupt(); Thread.currentThread().interrupt();
@@ -140,7 +136,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) {
logException(LOG, WARNING, e); if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
interrupt(); interrupt();
} }
} }
@@ -185,7 +181,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) {
logException(LOG, WARNING, e); if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
interrupt(); interrupt();
} }
} }

View File

@@ -12,7 +12,6 @@ import org.briarproject.bramble.api.sync.SyncRecordWriterFactory;
import org.briarproject.bramble.api.sync.SyncSession; import org.briarproject.bramble.api.sync.SyncSession;
import org.briarproject.bramble.api.sync.SyncSessionFactory; import org.briarproject.bramble.api.sync.SyncSessionFactory;
import org.briarproject.bramble.api.system.Clock; import org.briarproject.bramble.api.system.Clock;
import org.briarproject.bramble.api.transport.StreamWriter;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
@@ -54,21 +53,19 @@ class SyncSessionFactoryImpl implements SyncSessionFactory {
@Override @Override
public SyncSession createSimplexOutgoingSession(ContactId c, public SyncSession createSimplexOutgoingSession(ContactId c,
int maxLatency, StreamWriter streamWriter) { int maxLatency, OutputStream out) {
OutputStream out = streamWriter.getOutputStream();
SyncRecordWriter recordWriter = SyncRecordWriter recordWriter =
recordWriterFactory.createRecordWriter(out); recordWriterFactory.createRecordWriter(out);
return new SimplexOutgoingSession(db, dbExecutor, eventBus, c, return new SimplexOutgoingSession(db, dbExecutor, eventBus, c,
maxLatency, streamWriter, recordWriter); maxLatency, recordWriter);
} }
@Override @Override
public SyncSession createDuplexOutgoingSession(ContactId c, int maxLatency, public SyncSession createDuplexOutgoingSession(ContactId c, int maxLatency,
int maxIdleTime, StreamWriter streamWriter) { int maxIdleTime, OutputStream out) {
OutputStream out = streamWriter.getOutputStream();
SyncRecordWriter recordWriter = SyncRecordWriter recordWriter =
recordWriterFactory.createRecordWriter(out); recordWriterFactory.createRecordWriter(out);
return new DuplexOutgoingSession(db, dbExecutor, eventBus, clock, c, return new DuplexOutgoingSession(db, dbExecutor, eventBus, clock, c,
maxLatency, maxIdleTime, streamWriter, recordWriter); maxLatency, maxIdleTime, recordWriter);
} }
} }

View File

@@ -40,7 +40,6 @@ 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
@@ -111,7 +110,7 @@ class ValidationManagerImpl implements ValidationManager, Service,
} }
validateNextMessageAsync(unvalidated); validateNextMessageAsync(unvalidated);
} catch (DbException e) { } catch (DbException e) {
logException(LOG, WARNING, e); if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
} }
} }
@@ -145,7 +144,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) {
logException(LOG, WARNING, e); if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
} }
} }
@@ -166,7 +165,7 @@ class ValidationManagerImpl implements ValidationManager, Service,
} }
deliverNextPendingMessageAsync(pending); deliverNextPendingMessageAsync(pending);
} catch (DbException e) { } catch (DbException e) {
logException(LOG, WARNING, e); if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
} }
} }
@@ -232,7 +231,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) {
logException(LOG, WARNING, e); if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
} }
} }
@@ -253,7 +252,8 @@ 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) {
logException(LOG, INFO, e); if (LOG.isLoggable(INFO))
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) {
logException(LOG, WARNING, e); if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
} }
} }
@@ -377,7 +377,7 @@ class ValidationManagerImpl implements ValidationManager, Service,
} }
shareNextMessageAsync(toShare); shareNextMessageAsync(toShare);
} catch (DbException e) { } catch (DbException e) {
logException(LOG, WARNING, e); if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), 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) {
logException(LOG, WARNING, e); if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), 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) {
logException(LOG, WARNING, e); if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), 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) {
logException(LOG, WARNING, e); if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
} }
} }

View File

@@ -13,7 +13,6 @@ 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
@@ -50,7 +49,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
logException(LOG, WARNING, e); if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
} }
} }

View File

@@ -10,7 +10,6 @@ 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 {
@@ -40,7 +39,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
logException(LOG, WARNING, e); if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
} }
} }

View File

@@ -99,18 +99,39 @@ class KeyManagerImpl implements KeyManager, Service, EventListener {
} }
@Override @Override
public Map<TransportId, KeySetId> addContact(Transaction txn, ContactId c, public void addContact(Transaction txn, ContactId c, SecretKey master,
SecretKey master, long timestamp, boolean alice, boolean active) long timestamp, boolean alice) throws DbException {
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.addContact(txn, c, master, timestamp, alice, active)); ids.put(t, m.addUnboundKeys(txn, master, timestamp, alice));
} }
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 {
@@ -125,10 +146,24 @@ 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 && m.canSendOutgoingStreams(c); return m == null ? false : m.canSendOutgoingStreams(c);
} }
@Override @Override

View File

@@ -3,28 +3,32 @@ 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;
class MutableKeySet { import javax.annotation.Nullable;
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;
MutableKeySet(KeySetId keySetId, ContactId contactId, public MutableKeySet(KeySetId keySetId, @Nullable ContactId contactId,
MutableTransportKeys transportKeys) { MutableTransportKeys transportKeys) {
this.keySetId = keySetId; this.keySetId = keySetId;
this.contactId = contactId; this.contactId = contactId;
this.transportKeys = transportKeys; this.transportKeys = transportKeys;
} }
KeySetId getKeySetId() { public KeySetId getKeySetId() {
return keySetId; return keySetId;
} }
ContactId getContactId() { @Nullable
public ContactId getContactId() {
return contactId; return contactId;
} }
MutableTransportKeys getTransportKeys() { public MutableTransportKeys getTransportKeys() {
return transportKeys; return transportKeys;
} }
} }

View File

@@ -4,7 +4,6 @@ import org.briarproject.bramble.api.crypto.SecretKey;
import org.briarproject.bramble.api.crypto.StreamEncrypterFactory; import org.briarproject.bramble.api.crypto.StreamEncrypterFactory;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.transport.StreamContext; import org.briarproject.bramble.api.transport.StreamContext;
import org.briarproject.bramble.api.transport.StreamWriter;
import org.briarproject.bramble.api.transport.StreamWriterFactory; import org.briarproject.bramble.api.transport.StreamWriterFactory;
import java.io.OutputStream; import java.io.OutputStream;
@@ -24,14 +23,14 @@ class StreamWriterFactoryImpl implements StreamWriterFactory {
} }
@Override @Override
public StreamWriter createStreamWriter(OutputStream out, public OutputStream createStreamWriter(OutputStream out,
StreamContext ctx) { StreamContext ctx) {
return new StreamWriterImpl( return new StreamWriterImpl(
streamEncrypterFactory.createStreamEncrypter(out, ctx)); streamEncrypterFactory.createStreamEncrypter(out, ctx));
} }
@Override @Override
public StreamWriter createContactExchangeStreamWriter(OutputStream out, public OutputStream createContactExchangeStreamWriter(OutputStream out,
SecretKey headerKey) { SecretKey headerKey) {
return new StreamWriterImpl( return new StreamWriterImpl(
streamEncrypterFactory.createContactExchangeStreamDecrypter(out, streamEncrypterFactory.createContactExchangeStreamDecrypter(out,

View File

@@ -2,7 +2,6 @@ package org.briarproject.bramble.transport;
import org.briarproject.bramble.api.crypto.StreamEncrypter; import org.briarproject.bramble.api.crypto.StreamEncrypter;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.transport.StreamWriter;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;
@@ -18,7 +17,7 @@ import static org.briarproject.bramble.api.transport.TransportConstants.MAX_PAYL
*/ */
@NotThreadSafe @NotThreadSafe
@NotNullByDefault @NotNullByDefault
class StreamWriterImpl extends OutputStream implements StreamWriter { class StreamWriterImpl extends OutputStream {
private final StreamEncrypter encrypter; private final StreamEncrypter encrypter;
private final byte[] payload; private final byte[] payload;
@@ -30,17 +29,6 @@ class StreamWriterImpl extends OutputStream implements StreamWriter {
payload = new byte[MAX_PAYLOAD_LENGTH]; payload = new byte[MAX_PAYLOAD_LENGTH];
} }
@Override
public OutputStream getOutputStream() {
return this;
}
@Override
public void sendEndOfStream() throws IOException {
writeFrame(true);
encrypter.flush();
}
@Override @Override
public void close() throws IOException { public void close() throws IOException {
writeFrame(true); writeFrame(true);

View File

@@ -15,11 +15,18 @@ interface TransportKeyManager {
void start(Transaction txn) throws DbException; void start(Transaction txn) throws DbException;
KeySetId addContact(Transaction txn, ContactId c, SecretKey master, void addContact(Transaction txn, ContactId c, SecretKey master,
long timestamp, boolean alice, boolean active) throws DbException; long timestamp, boolean alice) 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);

Some files were not shown because too many files have changed in this diff Show More