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:
before_script:
- set -e
- export GRADLE_USER_HOME=$PWD/.gradle
cache:
paths:
- .gradle/wrapper
- .gradle/caches
script:
- ./gradlew --no-daemon animalSnifferMain animalSnifferTest
- ./gradlew --no-daemon test
- ./gradlew test
after_script:
# these file change every time but should not be cached
after_script:
# this file changes every time but should not be cached
- rm -f $GRADLE_USER_HOME/caches/modules-2/modules-2.lock
- 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: 'witness'
apply plugin: 'de.undercouch.download'
android {
compileSdkVersion 27
@@ -8,11 +14,9 @@ android {
defaultConfig {
minSdkVersion 14
targetSdkVersion 26
versionCode 10012
versionName "1.0.12"
versionCode 10001
versionName "1.0.1"
consumerProguardFiles 'proguard-rules.txt'
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
compileOptions {
@@ -21,54 +25,43 @@ android {
}
}
configurations {
tor
}
dependencies {
implementation project(path: ':bramble-core', configuration: 'default')
implementation 'org.briarproject:jtorctl:0.3'
tor 'org.briarproject:tor-android:0.2.9.16@zip'
implementation fileTree(dir: 'libs', include: '*.jar')
annotationProcessor 'com.google.dagger:dagger-compiler:2.0.2'
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 {
verify = [
'com.android.tools.analytics-library:protos:26.1.3:protos-26.1.3.jar:818c9f256f141d9dafec03a1aa2b94d240b2c140acfd7ee31a8b3e6c2b9479e3',
'com.android.tools.analytics-library:shared:26.1.3:shared-26.1.3.jar:7110706c7ada96c8b6f5ca80c478291bc7899d46277de2c48527e045442401a3',
'com.android.tools.analytics-library:tracker:26.1.3:tracker-26.1.3.jar:4155424bf2ce4872da83332579a1707252bc66cbd77c5144fdc4483d0f2e1418',
'com.android.tools.build:apksig:3.1.3:apksig-3.1.3.jar:7e1f8e675a6e768e5b56405e41d6c3cc05befe62e601b04177de1029902c9c89',
'com.android.tools.build:builder-model:3.1.3:builder-model-3.1.3.jar:06ad1c422d679fc698451479cb40ba863849d67bfd1de23f6d2c16d78b024b0b',
'com.android.tools.build:builder-test-api:3.1.3:builder-test-api-3.1.3.jar:4d989f780436794f0f8b2f50e9e079b786571eac90f26c208ab2ae6d4012f389',
'com.android.tools.build:builder:3.1.3:builder-3.1.3.jar:8a1092012c89d0ec1ee2eff09c5708c71ef4482a6862df8d3a44a67fccace01c',
'com.android.tools.build:gradle-api:3.1.3:gradle-api-3.1.3.jar:01e4df521456aef66514336f1d492346730dd1fb8f6433a89f62da834941ed72',
'com.android.tools.build:manifest-merger:26.1.3:manifest-merger-26.1.3.jar:1e4fc7e932adb4607082409800e5e6fccb42e6c5360ae5990094bf522f3ada55',
'com.android.tools.ddms:ddmlib:26.1.3:ddmlib-26.1.3.jar:c54931cd68df5d1ea2923b3b320eae47cd2307a5a916bb8674c0acf93cd1d3cd',
'com.android.tools.external.com-intellij:intellij-core:26.1.3:intellij-core-26.1.3.jar:af67f5535fef2e1a28b1007a4acb8c5deb6a1e33b8afe7b11d012c9e778ebcec',
'com.android.tools.external.com-intellij:kotlin-compiler:26.1.3:kotlin-compiler-26.1.3.jar:c746d2859dc11cc05c84b692b3498d3a621e0929511f8440ee009c6557838fd4',
'com.android.tools.external.org-jetbrains:uast:26.1.3:uast-26.1.3.jar:3f3f6651d0c7685a77ecb22e9c82d6b49fdf24322c17360768dc530678f43265',
'com.android.tools.layoutlib:layoutlib-api:26.1.3:layoutlib-api-26.1.3.jar:10bc73ce706c45629872d6a999dbe12116df64e24f47ff93b7b13121ff57b4b0',
'com.android.tools.lint:lint-api:26.1.3:lint-api-26.1.3.jar:6f97323f9af8deda86278717885b5c927f3766757db89709f52d11d42b6fb751',
'com.android.tools.lint:lint-checks:26.1.3:lint-checks-26.1.3.jar:73c3d53784c9ce3e6d5968506581918e0179645d20809927ca4a001dd766b001',
'com.android.tools.lint:lint-gradle-api:26.1.3:lint-gradle-api-26.1.3.jar:7ca3c4866ec21dc21d53a9d86f752b77ace6f6c610a0c9dc877313856c733d9d',
'com.android.tools.lint:lint-gradle:26.1.3:lint-gradle-26.1.3.jar:db0c354b8f4b6f6637e31f91c564785a59ff896325331fcbc3de7458e0b6c067',
'com.android.tools.lint:lint-kotlin:26.1.3:lint-kotlin-26.1.3.jar:94e2b0f4565a241561cfb8fc1222bb3f132a3b98d2a90421dbb72ee8358e7d68',
'com.android.tools.lint:lint:26.1.3:lint-26.1.3.jar:8d5f32c989c6d191d712e90ad3ca2d1c409313599551d04d834caa44d26c78df',
'com.android.tools:annotations:26.1.3:annotations-26.1.3.jar:c950430b24ac5d58fc97e7283b8f0115f99587e76e08b4e1e2aaa780f2d77323',
'com.android.tools:common:26.1.3:common-26.1.3.jar:7c31a90581a148ab219f615a59667f0dded7fa39b248529784474da3c2274ef2',
'com.android.tools:dvlib:26.1.3:dvlib-26.1.3.jar:0cae87906f53d3f1088366a916ed180a7312b6d9919b90797f238875c8492855',
'com.android.tools:repository:26.1.3:repository-26.1.3.jar:52d4539cc68db91b261e2a33b2c8206b26e05539078758dc28cfb3854adb4f59',
'com.android.tools:sdk-common:26.1.3:sdk-common-26.1.3.jar:1948603ca9ff22c7ebb3178000bffa3a9dd2ca1cc5cb0c793cae08468b8fcfc1',
'com.android.tools:sdklib:26.1.3:sdklib-26.1.3.jar:4adcfaad9514607098d2c51503c39811112d3050f4d1e744c01c7f08f591032b',
'com.android.tools.analytics-library:protos:26.1.2:protos-26.1.2.jar:52672a0b42b572a06aecc3535d5068eb46c0e15d129b9f1085d3c16a1da5cdbb',
'com.android.tools.analytics-library:shared:26.1.2:shared-26.1.2.jar:5c7e0eda18c6f87feeb83628c707e8aaa3298b41fb72e38efe31ad1675f9e8e9',
'com.android.tools.analytics-library:tracker:26.1.2:tracker-26.1.2.jar:06f97aa0adf44ffb06f8681c6a79d9be153a08f61d21eddc42b8d3db96df4282',
'com.android.tools.build:apksig:3.1.2:apksig-3.1.2.jar:40696a4559124d1d57873d208857eee059d48859239d569c7d18374ac644a8be',
'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.2:builder-test-api-3.1.2.jar:dfe2a50b740d41b11189101062434d4283d18647e89a492ad51710c719363e9f',
'com.android.tools.build:builder:3.1.2:builder-3.1.2.jar:b60f825a42e2efe8433619fbc759f3d9effecab718279048d36881188ceb1d14',
'com.android.tools.build:gradle-api:3.1.2:gradle-api-3.1.2.jar:e58bcc5b893e4583ab0f5c8ef89c4dbcce202b405a9d7fcc116d21e5357d4893',
'com.android.tools.build:manifest-merger:26.1.2:manifest-merger-26.1.2.jar:9c61c27ea5266573107b954acf1216d398f4d7e7ae6fad6409d6b2b767eb091c',
'com.android.tools.ddms:ddmlib:26.1.2:ddmlib-26.1.2.jar:18a2a5fbef36882f07d03c2b9e59eba05cf8248177bf5cbff736e4b582804c44',
'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.2:kotlin-compiler-26.1.2.jar:152df0bee7580326c77316b669a9d96e3b09efb1d45f545dce4147271b0b8944',
'com.android.tools.external.org-jetbrains:uast:26.1.2:uast-26.1.2.jar:02d39582206d3f5fc0a6cb18bfd9e8b9f9c1acb805ec6dac08b4e3a56849d279',
'com.android.tools.layoutlib:layoutlib-api:26.1.2:layoutlib-api-26.1.2.jar:20220039fcc7d799f928153beff862e704457c0f55ab44258f3745ebeb662b4f',
'com.android.tools.lint:lint-api:26.1.2:lint-api-26.1.2.jar:e1d5b62b870a7c566e9877a6b96b27784a4d713f8caa07fdcb4705d47a40a1d9',
'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.2:lint-gradle-api-26.1.2.jar:71284f2a8b03c3e55c94511c9eb36f8184fbb85324325fc6b78abf5183f03d90',
'com.android.tools.lint:lint-gradle:26.1.2:lint-gradle-26.1.2.jar:855f0c82b7fc690df1b7319c0774f7517f7f8f5dd4eee1f6077dcf50e07c6240',
'com.android.tools.lint:lint-kotlin:26.1.2:lint-kotlin-26.1.2.jar:1e591f70bcbbc11569720a9bbcca2bc1f3d4f789f01f40f642848d920643d484',
'com.android.tools.lint:lint:26.1.2:lint-26.1.2.jar:93736c62e9f1976998c2b4aa716aea0734cdb162d05502f4af7292654aedb182',
'com.android.tools:annotations:26.1.2:annotations-26.1.2.jar:72773dcaf5c4ccca828e3c8467f1b78a8a00b3cc5f8ad1aab88fcf9379928018',
'com.android.tools:common:26.1.2:common-26.1.2.jar:ea4320f0c17dcbc4491896bb705c4d25ec08bd62ef02ab0579fe154e75e788e6',
'com.android.tools:dvlib:26.1.2:dvlib-26.1.2.jar:1187aa4fb666595c96c4deb6bc0e0f4b7e396bde9f6243330b49a232946130ea',
'com.android.tools:repository:26.1.2:repository-26.1.2.jar:8b86e512ad6d32bd76989451eefe2b271f5efce6d4d65ecb173afaf14606e01a',
'com.android.tools:sdk-common:26.1.2:sdk-common-26.1.2.jar:23584720a60a21cdcb5b1ec10269e3013789d6805d153cc696c39ec7ce251896',
'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.gson:gson:2.7:gson-2.7.jar:2d43eb5ea9e133d2ee2405cc14f5ee08951b8361302fdd93494a3a997b508d32',
'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.bouncycastle:bcpkix-jdk15on:1.56:bcpkix-jdk15on-1.56.jar:7043dee4e9e7175e93e0b36f45b1ec1ecb893c5f755667e8b916eb8dd201c6ca',
'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.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',
@@ -121,9 +112,81 @@ dependencyVerification {
]
}
project.afterEvaluate {
copy {
from configurations.tor.collect { zipTree(it) }
into 'src/main/res/raw'
ext.torBinaryDir = 'src/main/res/raw'
ext.torVersion = '0.2.9.14'
ext.geoipVersion = '2017-11-06'
ext.torDownloadUrl = 'https://briarproject.org/build/'
def torBinaries = [
"tor_arm" : '1710ea6c47b7f4c1a88bdf4858c7893837635db10e8866854eed8d61629f50e8',
"tor_arm_pie": '974e6949507db8fa2ea45231817c2c3677ed4ccf5488a2252317d744b0be1917',
"tor_x86" : '3a5e45b3f051fcda9353b098b7086e762ffe7ba9242f7d7c8bf6523faaa8b1e9',
"tor_x86_pie": 'd1d96d8ce1a4b68accf04850185780d10cd5563d3552f7e1f040f8ca32cb4e51',
"geoip" : '8239b98374493529a29096e45fc5877d4d6fdad0146ad8380b291f90d61484ea'
]
def verifyOrDeleteBinary(name, chksum, alreadyVerified) {
return tasks.create("verifyOrDeleteBinary${name}", VerifyOrDelete) {
src "${torBinaryDir}/${name}.zip"
algorithm 'SHA-256'
checksum chksum
result alreadyVerified
onlyIf {
src.exists()
}
}
}
def downloadBinary(name, chksum, alreadyVerified) {
return tasks.create([
name: "downloadBinary${name}",
type: Download,
dependsOn: verifyOrDeleteBinary(name, chksum, alreadyVerified)]) {
src "${torDownloadUrl}${name}.zip"
.replace('tor_', "tor-${torVersion}-")
.replace('geoip', "geoip-${geoipVersion}")
.replaceAll('_', '-')
dest "${torBinaryDir}/${name}.zip"
onlyIf {
!dest.exists()
}
}
}
def verifyBinary(name, chksum) {
boolean[] alreadyVerified = [false]
return tasks.create([
name : "verifyBinary${name}",
type : Verify,
dependsOn: downloadBinary(name, chksum, alreadyVerified)]) {
src "${torBinaryDir}/${name}.zip"
algorithm 'SHA-256'
checksum chksum
onlyIf {
!alreadyVerified[0]
}
}
}
project.afterEvaluate {
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"
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_WIFI_STATE"/>
<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.READ_LOGS"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<application

View File

@@ -1,25 +1,13 @@
package org.briarproject.bramble;
import android.app.Application;
import org.briarproject.bramble.plugin.tor.CircumventionProvider;
import org.briarproject.bramble.plugin.tor.CircumventionProviderImpl;
import org.briarproject.bramble.plugin.AndroidPluginModule;
import org.briarproject.bramble.system.AndroidSystemModule;
import javax.inject.Singleton;
import dagger.Module;
import dagger.Provides;
@Module(includes = {
AndroidPluginModule.class,
AndroidSystemModule.class
})
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_ON;
import static java.util.logging.Level.WARNING;
import static org.briarproject.bramble.util.LogUtils.logException;
@MethodsNotNullByDefault
@ParametersNotNullByDefault
@@ -146,7 +145,7 @@ class AndroidBluetoothPlugin extends BluetoothPlugin<BluetoothServerSocket> {
try {
if (ss != null) ss.close();
} 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 {
if (c != null) c.close();
} 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.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.FileObserver;
import android.os.PowerManager;
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.DuplexTransportConnection;
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.event.SettingsUpdatedEvent;
import org.briarproject.bramble.api.system.Clock;
import org.briarproject.bramble.api.system.LocationUtils;
import org.briarproject.bramble.util.AndroidUtils;
import org.briarproject.bramble.util.IoUtils;
import org.briarproject.bramble.util.RenewableWakeLock;
import org.briarproject.bramble.util.StringUtils;
import java.io.Closeable;
@@ -50,7 +51,6 @@ import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
@@ -58,6 +58,7 @@ import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Scanner;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
import java.util.concurrent.Future;
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.PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED;
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.logging.Level.INFO;
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_PORT;
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;
@MethodsNotNullByDefault
@@ -104,11 +105,8 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
"CIRC", "ORCONN", "HS_DESC", "NOTICE", "WARN", "ERR"
};
private static final String OWNER = "__OwningControllerProcess";
private static final int COOKIE_TIMEOUT_MS = 3000;
private static final int COOKIE_POLLING_INTERVAL_MS = 200;
private static final int COOKIE_TIMEOUT = 3000; // Milliseconds
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 =
Logger.getLogger(TorPlugin.class.getName());
@@ -116,17 +114,16 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
private final ScheduledExecutorService scheduler;
private final Context appContext;
private final LocationUtils locationUtils;
private final DevReporter reporter;
private final SocketFactory torSocketFactory;
private final Clock clock;
private final Backoff backoff;
private final DuplexPluginCallback callback;
private final String architecture;
private final CircumventionProvider circumventionProvider;
private final int maxLatency, maxIdleTime, socketTimeout;
private final ConnectionStatus connectionStatus;
private final File torDirectory, torFile, geoIpFile, configFile;
private final File doneFile, cookieFile;
private final RenewableWakeLock wakeLock;
private final PowerManager.WakeLock wakeLock;
private final AtomicReference<Future<?>> connectivityCheck =
new AtomicReference<>();
private final AtomicBoolean used = new AtomicBoolean(false);
@@ -139,19 +136,18 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
TorPlugin(Executor ioExecutor, ScheduledExecutorService scheduler,
Context appContext, LocationUtils locationUtils,
SocketFactory torSocketFactory, Clock clock, Backoff backoff,
DuplexPluginCallback callback, String architecture,
CircumventionProvider circumventionProvider, int maxLatency, int maxIdleTime) {
DevReporter reporter, SocketFactory torSocketFactory,
Backoff backoff, DuplexPluginCallback callback,
String architecture, int maxLatency, int maxIdleTime) {
this.ioExecutor = ioExecutor;
this.scheduler = scheduler;
this.appContext = appContext;
this.locationUtils = locationUtils;
this.reporter = reporter;
this.torSocketFactory = torSocketFactory;
this.clock = clock;
this.backoff = backoff;
this.callback = callback;
this.architecture = architecture;
this.circumventionProvider = circumventionProvider;
this.maxLatency = maxLatency;
this.maxIdleTime = maxIdleTime;
if (maxIdleTime > Integer.MAX_VALUE / 2)
@@ -164,13 +160,14 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
configFile = new File(torDirectory, "torrc");
doneFile = new File(torDirectory, "done");
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
connectionStatusExecutor = new PoliteExecutor("TorPlugin",
ioExecutor, 1);
PowerManager pm = (PowerManager)
appContext.getSystemService(POWER_SERVICE);
wakeLock = new RenewableWakeLock(pm, scheduler, PARTIAL_WAKE_LOCK,
WAKE_LOCK_TAG, 1, MINUTES);
}
@Override
@@ -193,10 +190,18 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
if (used.getAndSet(true)) throw new IllegalStateException();
// Install or update the assets if necessary
if (!assetsAreUpToDate()) installAssets();
if (cookieFile.exists() && !cookieFile.delete())
LOG.warning("Old auth cookie not deleted");
// Start a new Tor process
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 configPath = configFile.getAbsolutePath();
String pid = String.valueOf(android.os.Process.myPid());
@@ -235,16 +240,11 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
throw new PluginException();
}
// Wait for the auth cookie file to be created/updated
long start = clock.currentTimeMillis();
while (cookieFile.length() < 32) {
if (clock.currentTimeMillis() - start > COOKIE_TIMEOUT_MS) {
LOG.warning("Auth cookie not created");
if (LOG.isLoggable(INFO)) listFiles(torDirectory);
throw new PluginException();
}
Thread.sleep(COOKIE_POLLING_INTERVAL_MS);
if (!latch.await(COOKIE_TIMEOUT, MILLISECONDS)) {
LOG.warning("Auth cookie not created");
if (LOG.isLoggable(INFO)) listFiles(torDirectory);
throw new PluginException();
}
LOG.info("Auth cookie created");
} catch (InterruptedException e) {
LOG.warning("Interrupted while starting Tor");
Thread.currentThread().interrupt();
@@ -338,7 +338,7 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
return zin;
}
private InputStream getConfigInputStream() {
private InputStream getConfigInputStream() throws IOException {
int resId = getResourceId("torrc");
return appContext.getResources().openRawResource(resId);
}
@@ -352,7 +352,7 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
try {
if (c != null) c.close();
} 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 {
if (s != null) s.close();
} 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();
if (children != null) for (File child : children) listFiles(child);
} 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() {
ioExecutor.execute(() -> {
// 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.bind(new InetSocketAddress("127.0.0.1", port));
} catch (IOException e) {
logException(LOG, WARNING, e);
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
tryToClose(ss);
return;
}
@@ -428,7 +436,7 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
try {
if (ss != null) ss.close();
} catch (IOException e) {
logException(LOG, WARNING, e);
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
} finally {
callback.transportDisabled();
}
@@ -447,7 +455,7 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
response = controlConnection.addOnion(portLines);
else response = controlConnection.addOnion(privKey, portLines);
} catch (IOException e) {
logException(LOG, WARNING, e);
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
return;
}
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
public void stop() {
public void stop() throws PluginException {
running = false;
tryToClose(socket);
if (networkStateReceiver != null)
@@ -526,7 +523,7 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
controlConnection.shutdownTor("TERM");
controlSocket.close();
} catch (IOException e) {
logException(LOG, WARNING, e);
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
}
}
wakeLock.release();
@@ -548,16 +545,20 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
}
@Override
public void poll(Map<ContactId, TransportProperties> contacts) {
public void poll(Collection<ContactId> connected) {
if (!isRunning()) return;
backoff.increment();
for (Entry<ContactId, TransportProperties> e : contacts.entrySet()) {
connectAndCallBack(e.getKey(), e.getValue());
Map<ContactId, TransportProperties> remote =
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) {
ioExecutor.execute(() -> {
if (!isRunning()) return;
DuplexTransportConnection d = createConnection(p);
if (d != null) {
backoff.reset();
@@ -567,8 +568,13 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
}
@Override
public DuplexTransportConnection createConnection(TransportProperties p) {
public DuplexTransportConnection createConnection(ContactId c) {
if (!isRunning()) return null;
return createConnection(callback.getRemoteProperties(c));
}
@Nullable
private DuplexTransportConnection createConnection(TransportProperties p) {
String onion = p.get(PROP_ONION);
if (StringUtils.isNullOrEmpty(onion)) return null;
if (!ONION.matcher(onion).matches()) {
@@ -618,7 +624,10 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
connectionStatus.getAndSetCircuitBuilt()) {
LOG.info("First circuit built");
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%")) {
connectionStatus.setBootstrapped();
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");
}
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
public void eventOccurred(Event e) {
if (e instanceof SettingsUpdatedEvent) {
@@ -677,8 +705,8 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
boolean online = net != null && net.isConnected();
boolean wifi = online && net.getType() == TYPE_WIFI;
String country = locationUtils.getCurrentCountry();
boolean blocked =
circumventionProvider.isTorProbablyBlocked(country);
boolean blocked = TorNetworkMetadata.isTorProbablyBlocked(
country);
Settings s = callback.getSettings();
int network = s.getInt(PREF_TOR_NETWORK, PREF_TOR_NETWORK_ALWAYS);
@@ -692,26 +720,19 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
if (!online) {
LOG.info("Disabling network, device is offline");
enableNetwork(false);
} else if (blocked) {
LOG.info("Disabling network, country is blocked");
enableNetwork(false);
} else if (network == PREF_TOR_NETWORK_NEVER
|| (network == PREF_TOR_NETWORK_WIFI && !wifi)) {
LOG.info("Disabling network due to data setting");
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 {
LOG.info("Enabling network");
enableBridges(false);
enableNetwork(true);
}
} 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.DuplexPluginCallback;
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.util.AndroidUtils;
@@ -40,27 +40,24 @@ public class TorPluginFactory implements DuplexPluginFactory {
private final ScheduledExecutorService scheduler;
private final Context appContext;
private final LocationUtils locationUtils;
private final DevReporter reporter;
private final EventBus eventBus;
private final SocketFactory torSocketFactory;
private final BackoffFactory backoffFactory;
private final CircumventionProvider circumventionProvider;
private final Clock clock;
public TorPluginFactory(Executor ioExecutor,
ScheduledExecutorService scheduler, Context appContext,
LocationUtils locationUtils, EventBus eventBus,
SocketFactory torSocketFactory, BackoffFactory backoffFactory,
CircumventionProvider circumventionProvider,
Clock clock) {
LocationUtils locationUtils, DevReporter reporter,
EventBus eventBus, SocketFactory torSocketFactory,
BackoffFactory backoffFactory) {
this.ioExecutor = ioExecutor;
this.scheduler = scheduler;
this.appContext = appContext;
this.locationUtils = locationUtils;
this.reporter = reporter;
this.eventBus = eventBus;
this.torSocketFactory = torSocketFactory;
this.backoffFactory = backoffFactory;
this.circumventionProvider = circumventionProvider;
this.clock = clock;
}
@Override
@@ -97,8 +94,8 @@ public class TorPluginFactory implements DuplexPluginFactory {
Backoff backoff = backoffFactory.createBackoff(MIN_POLLING_INTERVAL,
MAX_POLLING_INTERVAL, BACKOFF_BASE);
TorPlugin plugin = new TorPlugin(ioExecutor, scheduler, appContext,
locationUtils, torSocketFactory, clock, backoff, callback,
architecture, circumventionProvider, MAX_LATENCY, MAX_IDLE_TIME);
locationUtils, reporter, torSocketFactory, backoff, callback,
architecture, MAX_LATENCY, MAX_IDLE_TIME);
eventBus.addListener(plugin);
return plugin;
}

View File

@@ -9,7 +9,6 @@ import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiManager;
import android.os.Build;
import android.os.Parcel;
import android.os.StrictMode;
import android.provider.Settings;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
@@ -67,12 +66,9 @@ class AndroidSecureRandomProvider extends LinuxSecureRandomProvider {
@Override
protected void writeSeed() {
// Silence strict mode
StrictMode.ThreadPolicy tp = StrictMode.allowThreadDiskWrites();
super.writeSeed();
if (Build.VERSION.SDK_INT >= 16 && Build.VERSION.SDK_INT <= 18)
applyOpenSslFix();
StrictMode.setThreadPolicy(tp);
}
// Based on https://android-developers.googleblog.com/2013/08/some-securerandom-thoughts.html

View File

@@ -1,9 +1,7 @@
package org.briarproject.bramble.util;
import android.annotation.SuppressLint;
import android.bluetooth.BluetoothAdapter;
import android.content.Context;
import android.content.SharedPreferences;
import android.os.Build;
import android.provider.Settings;
@@ -12,15 +10,11 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.logging.Logger;
import static android.content.Context.MODE_PRIVATE;
public class AndroidUtils {
private static final Logger LOG =
Logger.getLogger(AndroidUtils.class.getName());
// Fake Bluetooth address returned by BluetoothAdapter on API 23 and later
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,
BluetoothAdapter adapter) {
// Return the adapter's address if it's valid and not fake
@SuppressLint("HardwareIds")
String address = adapter.getAddress();
if (isValidBluetoothAddress(address)) return address;
// Return the address from settings if it's valid and not fake
@@ -58,28 +51,17 @@ public class AndroidUtils {
&& !address.equals(FAKE_BLUETOOTH_ADDRESS);
}
public static void deleteAppData(Context ctx, SharedPreferences... clear) {
// 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
public static void deleteAppData(Context ctx) {
File dataDir = new File(ctx.getApplicationInfo().dataDir);
File[] children = dataDir.listFiles();
if (children == null) {
LOG.warning("Could not list files in app data dir");
} else {
if (children != null) {
for (File child : children) {
String name = child.getName();
if (!name.equals("lib") && !name.equals("shared_prefs")) {
if (!child.getName().equals("lib"))
IoUtils.deleteFileOrDir(child);
}
}
}
// Recreate the cache dir as some OpenGL drivers expect it to exist
if (!new File(dataDir, "cache").mkdir())
LOG.warning("Could not recreate cache dir");
new File(dataDir, "cache").mkdir();
}
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
targetCompatibility = 1.8
apply plugin: 'ru.vyarus.animalsniffer'
apply plugin: 'witness'
dependencies {
@@ -15,8 +14,6 @@ dependencies {
testImplementation "org.jmock:jmock-legacy:2.8.2"
testImplementation "org.hamcrest:hamcrest-library:1.3"
testImplementation "org.hamcrest:hamcrest-core:1.3"
signature 'org.codehaus.mojo.signature:java16:1.1@signature'
}
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:1.9.4:ant-1.9.4.jar:649ae0730251de07b8913f49286d46bba7b92d47c5f332610aa426c4f02161d8',
'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-library:1.3:hamcrest-library-1.3.jar:711d64522f9ec410983bd310934296da134be4254a125080a0416ec178dfad1c',
'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:2.8.2:jmock-2.8.2.jar:6c73cb4a2e6dbfb61fd99c9a768539c170ab6568e57846bd60dbf19596b65b16',
'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',
]
}
@@ -55,3 +48,8 @@ task jarTest(type: Jar, dependsOn: testClasses) {
artifacts {
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
*/
ContactId addContact(Author remote, AuthorId local, SecretKey master,
long timestamp, boolean alice, boolean verified, boolean active)
throws DbException;
ContactId addContact(Author remote, AuthorId local,
SecretKey master, long timestamp, boolean alice, boolean verified,
boolean active) throws DbException;
/**
* 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;
/**
* 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
@NotNullByDefault

View File

@@ -8,7 +8,6 @@ import java.io.IOException;
public interface BdfReader {
int DEFAULT_NESTED_LIMIT = 5;
int DEFAULT_MAX_BUFFER_SIZE = 64 * 1024;
boolean eof() throws IOException;
@@ -40,13 +39,13 @@ public interface BdfReader {
boolean hasString() throws IOException;
String readString() throws IOException;
String readString(int maxLength) throws IOException;
void skipString() throws IOException;
boolean hasRaw() throws IOException;
byte[] readRaw() throws IOException;
byte[] readRaw(int maxLength) throws IOException;
void skipRaw() throws IOException;

View File

@@ -9,6 +9,5 @@ public interface BdfReaderFactory {
BdfReader createReader(InputStream in);
BdfReader createReader(InputStream in, int nestedLimit,
int maxBufferSize);
BdfReader createReader(InputStream in, int nestedLimit);
}

View File

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

View File

@@ -14,8 +14,6 @@ public interface DatabaseConfig {
File getDatabaseDirectory();
File getDatabaseKeyDirectory();
void setEncryptionKey(SecretKey key);
@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
* for annotating methods that should run on the IO executor.
* for annotating methods that should run on the UI executor.
* <p>
* The contract of this executor is that tasks may be run concurrently, and
* 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.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.properties.TransportProperties;
import java.util.Map;
import java.util.Collection;
@NotNullByDefault
public interface Plugin {
@@ -40,19 +39,21 @@ public interface Plugin {
boolean isRunning();
/**
* Returns true if the plugin should be polled periodically to attempt to
* establish connections.
* Returns true if the plugin's {@link #poll(Collection)} method should be
* called periodically to attempt to establish connections.
*/
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();
/**
* Attempts to establish connections to the given contacts, passing any
* created connections to the callback.
* Attempts to establish connections to contacts, passing any created
* 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;
import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.properties.TransportProperties;
import org.briarproject.bramble.api.settings.Settings;
import java.util.Map;
/**
* An interface through which a transport plugin interacts with the rest of
* the application.
@@ -22,7 +25,17 @@ public interface PluginCallback {
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);
@@ -32,12 +45,34 @@ public interface PluginCallback {
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();
/**
* Signals that the transport is disabled.
* Signal that the transport got disabled.
*/
void transportDisabled();
}

View File

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

View File

@@ -22,6 +22,11 @@ public interface TransportConnectionWriter {
*/
int getMaxIdleTime();
/**
* Returns the capacity of the transport connection in bytes.
*/
long getCapacity();
/**
* Returns an output stream for writing to the transport connection.
*/

View File

@@ -71,6 +71,11 @@ public abstract class AbstractDuplexTransportConnection
return plugin.getMaxIdleTime();
}
@Override
public long getCapacity() {
return Long.MAX_VALUE;
}
@Override
public OutputStream getOutputStream() throws IOException {
return AbstractDuplexTransportConnection.this.getOutputStream();

View File

@@ -1,10 +1,10 @@
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.keyagreement.KeyAgreementListener;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.plugin.Plugin;
import org.briarproject.bramble.api.properties.TransportProperties;
import javax.annotation.Nullable;
@@ -15,11 +15,12 @@ import javax.annotation.Nullable;
public interface DuplexPlugin extends Plugin {
/**
* Attempts to create and return a connection using the given transport
* properties. Returns null if a connection cannot be created.
* Attempts to create and return a connection to the given contact using
* the current transport and configuration properties. Returns null if a
* connection cannot be created.
*/
@Nullable
DuplexTransportConnection createConnection(TransportProperties p);
DuplexTransportConnection createConnection(ContactId c);
/**
* 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;
/**
* An interface through which a duplex plugin interacts with the rest of the
* application.
* An interface for handling connections created by a duplex transport plugin.
*/
@NotNullByDefault
public interface DuplexPluginCallback extends PluginCallback {

View File

@@ -1,10 +1,10 @@
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.plugin.Plugin;
import org.briarproject.bramble.api.plugin.TransportConnectionReader;
import org.briarproject.bramble.api.plugin.TransportConnectionWriter;
import org.briarproject.bramble.api.properties.TransportProperties;
import javax.annotation.Nullable;
@@ -15,16 +15,18 @@ import javax.annotation.Nullable;
public interface SimplexPlugin extends Plugin {
/**
* Attempts to create and return a reader for the given transport
* properties. Returns null if a reader cannot be created.
* Attempts to create and return a reader for the given contact using the
* current transport and configuration properties. Returns null if a reader
* cannot be created.
*/
@Nullable
TransportConnectionReader createReader(TransportProperties p);
TransportConnectionReader createReader(ContactId c);
/**
* Attempts to create and return a writer for the given transport
* properties. Returns null if a writer cannot be created.
* Attempts to create and return a writer for the given contact using the
* current transport and configuration properties. Returns null if a writer
* cannot be created.
*/
@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;
/**
* An interface through which a simplex plugin interacts with the rest of the
* application.
* An interface for handling readers and writers created by a simplex transport
* plugin.
*/
@NotNullByDefault
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.nullsafety.NotNullByDefault;
import java.io.File;
@NotNullByDefault
public interface DevConfig {
PublicKey getDevPublicKey();
String getDevOnionAddress();
File getReportDir();
}

View File

@@ -23,6 +23,8 @@ public interface DevReporter {
/**
* 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.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.transport.StreamWriter;
import java.io.InputStream;
import java.io.OutputStream;
@NotNullByDefault
public interface SyncSessionFactory {
@@ -12,8 +12,8 @@ public interface SyncSessionFactory {
SyncSession createIncomingSession(ContactId c, InputStream in);
SyncSession createSimplexOutgoingSession(ContactId c, int maxLatency,
StreamWriter streamWriter);
OutputStream out);
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 {
/**
* @see System#currentTimeMillis()
* @see {@link System#currentTimeMillis()}
*/
long currentTimeMillis();
/**
* @see Thread#sleep(long)
* @see {@link Thread#sleep(long)}
*/
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
* stores a set of transport keys for communicating with the contact over
* each transport and returns the key set IDs.
* each transport.
* <p/>
* {@link StreamContext StreamContexts} for the contact can be created
* after this method has returned.
*
* @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,
SecretKey master, long timestamp, boolean alice, boolean active)
void addContact(Transaction txn, ContactId c, SecretKey master,
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;
/**
* 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)
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
* 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.nullsafety.NotNullByDefault;
import javax.annotation.Nullable;
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
@NotNullByDefault
public class KeySet {
private final KeySetId keySetId;
@Nullable
private final ContactId contactId;
private final TransportKeys transportKeys;
public KeySet(KeySetId keySetId, ContactId contactId,
public KeySet(KeySetId keySetId, @Nullable ContactId contactId,
TransportKeys transportKeys) {
this.keySetId = keySetId;
this.contactId = contactId;
@@ -27,6 +30,7 @@ public class KeySet {
return keySetId;
}
@Nullable
public ContactId getContactId() {
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
* transport stream
*/
StreamWriter createStreamWriter(OutputStream out, StreamContext ctx);
OutputStream createStreamWriter(OutputStream out, StreamContext ctx);
/**
* Creates an {@link OutputStream OutputStream} for writing to a contact
* exchange stream.
*/
StreamWriter createContactExchangeStreamWriter(OutputStream out,
OutputStream createContactExchangeStreamWriter(OutputStream out,
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.OutputStream;
import java.net.Socket;
import java.util.logging.Logger;
import javax.annotation.Nullable;
import static java.util.logging.Level.WARNING;
@NotNullByDefault
public class IoUtils {
private static final Logger LOG = Logger.getLogger(IoUtils.class.getName());
public static void deleteFileOrDir(File f) {
if (f.isFile()) {
delete(f);
f.delete();
} else if (f.isDirectory()) {
File[] children = f.listFiles();
if (children == null) {
if (LOG.isLoggable(WARNING)) {
LOG.warning("Could not list files in "
+ f.getAbsolutePath());
}
} else {
if (children != null)
for (File child : children) deleteFileOrDir(child);
}
delete(f);
f.delete();
}
}
private static void delete(File f) {
if (!f.delete() && LOG.isLoggable(WARNING))
LOG.warning("Could not delete " + f.getAbsolutePath());
}
public static void copyAndClose(InputStream in, OutputStream out) {
public static void copyAndClose(InputStream in, OutputStream out)
throws IOException {
byte[] buf = new byte[4096];
try {
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");
}
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() {
return os != null && os.contains("Linux") && !isAndroid();
}

View File

@@ -2,7 +2,6 @@ apply plugin: 'java-library'
sourceCompatibility = 1.8
targetCompatibility = 1.8
apply plugin: 'ru.vyarus.animalsniffer'
apply plugin: 'net.ltgt.apt'
apply plugin: 'idea'
apply plugin: 'witness'
@@ -27,8 +26,6 @@ dependencies {
testImplementation "org.hamcrest:hamcrest-core:1.3"
testApt 'com.google.dagger:dagger-compiler:2.0.2'
signature 'org.codehaus.mojo.signature:java16:1.1@signature'
}
dependencyVerification {
@@ -47,9 +44,6 @@ dependencyVerification {
'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.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-library:1.3:hamcrest-library-1.3.jar:711d64522f9ec410983bd310934296da134be4254a125080a0416ec178dfad1c',
'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:2.8.2:jmock-2.8.2.jar:6c73cb4a2e6dbfb61fd99c9a768539c170ab6568e57846bd60dbf19596b65b16',
'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.whispersystems:curve25519-java:0.4.1:curve25519-java-0.4.1.jar:7dd659d8822c06c3aea1a47f18fac9e5761e29cab8100030b877db445005f03e',
]
@@ -75,3 +68,8 @@ task jarTest(type: Jar, dependsOn: testClasses) {
artifacts {
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.plugin.PluginModule;
import org.briarproject.bramble.properties.PropertiesModule;
import org.briarproject.bramble.reporting.ReportingModule;
import org.briarproject.bramble.sync.SyncModule;
import org.briarproject.bramble.system.SystemModule;
import org.briarproject.bramble.transport.TransportModule;
@@ -29,8 +28,6 @@ public interface BrambleCoreEagerSingletons {
void inject(PropertiesModule.EagerSingletons init);
void inject(ReportingModule.EagerSingletons init);
void inject(SyncModule.EagerSingletons init);
void inject(SystemModule.EagerSingletons init);

View File

@@ -59,7 +59,6 @@ public class BrambleCoreModule {
c.inject(new LifecycleModule.EagerSingletons());
c.inject(new PluginModule.EagerSingletons());
c.inject(new PropertiesModule.EagerSingletons());
c.inject(new ReportingModule.EagerSingletons());
c.inject(new SyncModule.EagerSingletons());
c.inject(new SystemModule.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.Queue;
import java.util.concurrent.Executor;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.annotation.concurrent.GuardedBy;
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}
@@ -20,6 +20,8 @@ import static org.briarproject.bramble.util.LogUtils.now;
@NotNullByDefault
public class PoliteExecutor implements Executor {
private static final Level LOG_LEVEL = FINE;
private final Object lock = new Object();
@GuardedBy("lock")
private final Queue<Runnable> queue = new LinkedList<>();
@@ -47,11 +49,11 @@ public class PoliteExecutor implements Executor {
@Override
public void execute(Runnable r) {
long submitted = now();
long submitted = System.currentTimeMillis();
Runnable wrapped = () -> {
if (log.isLoggable(FINE)) {
long queued = now() - submitted;
log.fine("Queue time " + queued + " ms");
if (log.isLoggable(LOG_LEVEL)) {
long queued = System.currentTimeMillis() - submitted;
log.log(LOG_LEVEL, "Queue time " + queued + " ms");
}
try {
r.run();

View File

@@ -6,14 +6,16 @@ import java.util.concurrent.BlockingQueue;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;
import static java.util.logging.Level.FINE;
import static org.briarproject.bramble.util.LogUtils.now;
@NotNullByDefault
public class TimeLoggingExecutor extends ThreadPoolExecutor {
private static final Level LOG_LEVEL = FINE;
private final Logger log;
public TimeLoggingExecutor(String tag, int corePoolSize, int maxPoolSize,
@@ -27,15 +29,15 @@ public class TimeLoggingExecutor extends ThreadPoolExecutor {
@Override
public void execute(Runnable r) {
if (log.isLoggable(FINE)) {
long submitted = now();
if (log.isLoggable(LOG_LEVEL)) {
long submitted = System.currentTimeMillis();
super.execute(() -> {
long started = now();
long started = System.currentTimeMillis();
long queued = started - submitted;
log.fine("Queue time " + queued + " ms");
log.log(LOG_LEVEL, "Queue time " + queued + " ms");
r.run();
long executing = now() - started;
log.fine("Execution time " + executing + " ms");
long executing = System.currentTimeMillis() - started;
log.log(LOG_LEVEL, "Execution time " + executing + " ms");
});
} else {
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.system.Clock;
import org.briarproject.bramble.api.transport.StreamReaderFactory;
import org.briarproject.bramble.api.transport.StreamWriter;
import org.briarproject.bramble.api.transport.StreamWriterFactory;
import java.io.EOFException;
@@ -46,7 +45,6 @@ import javax.inject.Inject;
import static java.util.logging.Level.WARNING;
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.util.LogUtils.logException;
import static org.briarproject.bramble.util.ValidationUtils.checkLength;
import static org.briarproject.bramble.util.ValidationUtils.checkSize;
@@ -123,7 +121,7 @@ class ContactExchangeTaskImpl extends Thread implements ContactExchangeTask {
in = conn.getReader().getInputStream();
out = conn.getWriter().getOutputStream();
} catch (IOException e) {
logException(LOG, WARNING, e);
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
listener.contactExchangeFailed();
tryToClose(conn);
return;
@@ -134,7 +132,7 @@ class ContactExchangeTaskImpl extends Thread implements ContactExchangeTask {
try {
localProperties = transportPropertyManager.getLocalProperties();
} catch (DbException e) {
logException(LOG, WARNING, e);
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
listener.contactExchangeFailed();
tryToClose(conn);
return;
@@ -154,11 +152,11 @@ class ContactExchangeTaskImpl extends Thread implements ContactExchangeTask {
recordReaderFactory.createRecordReader(streamReader);
// Create the writers
StreamWriter streamWriter =
OutputStream streamWriter =
streamWriterFactory.createContactExchangeStreamWriter(out,
alice ? aliceHeaderKey : bobHeaderKey);
RecordWriter recordWriter =
recordWriterFactory.createRecordWriter(streamWriter.getOutputStream());
recordWriterFactory.createRecordWriter(streamWriter);
// Derive the nonces to be signed
byte[] aliceNonce = crypto.mac(ALICE_NONCE_LABEL, masterSecret,
@@ -186,8 +184,8 @@ class ContactExchangeTaskImpl extends Thread implements ContactExchangeTask {
localSignature, localTimestamp);
recordWriter.flush();
}
// Send EOF on the outgoing stream
streamWriter.sendEndOfStream();
// Close the outgoing stream
recordWriter.close();
// Skip any remaining records from the incoming stream
try {
while (true) recordReader.readRecord();
@@ -195,7 +193,7 @@ class ContactExchangeTaskImpl extends Thread implements ContactExchangeTask {
LOG.info("End of stream");
}
} catch (IOException e) {
logException(LOG, WARNING, e);
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
listener.contactExchangeFailed();
tryToClose(conn);
return;
@@ -223,11 +221,11 @@ class ContactExchangeTaskImpl extends Thread implements ContactExchangeTask {
LOG.info("Pseudonym exchange succeeded");
listener.contactExchangeSucceeded(remoteInfo.author);
} catch (ContactExistsException e) {
logException(LOG, WARNING, e);
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
tryToClose(conn);
listener.duplicateContact(remoteInfo.author);
} catch (DbException e) {
logException(LOG, WARNING, e);
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
tryToClose(conn);
listener.contactExchangeFailed();
}
@@ -308,7 +306,7 @@ class ContactExchangeTaskImpl extends Thread implements ContactExchangeTask {
conn.getReader().dispose(true, true);
conn.getWriter().dispose(true);
} 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,
boolean active) throws DbException {
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);
for (ContactHook hook : hooks) hook.addingContact(txn, contact);
return c;

View File

@@ -32,8 +32,6 @@ import javax.inject.Inject;
import static java.util.logging.Level.INFO;
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
class CryptoComponentImpl implements CryptoComponent {
@@ -129,14 +127,16 @@ class CryptoComponentImpl implements CryptoComponent {
throw new IllegalArgumentException();
if (!(pub instanceof Curve25519PublicKey))
throw new IllegalArgumentException();
long start = now();
long now = System.currentTimeMillis();
byte[] secret = curve25519.calculateAgreement(pub.getEncoded(),
priv.getEncoded());
// If the shared secret is all zeroes, the public key is invalid
byte allZero = 0;
for (byte b : secret) allZero |= b;
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;
}

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) {
printUsage();
System.exit(1);
return;
}
SecureRandom random = new SecureRandom();
MessageEncrypter encrypter = new MessageEncrypter(random);
if (args[0].equals("generate")) {
if (args.length != 3) {
printUsage();
System.exit(1);
}
try {
generateKeyPair(args[1], args[2]);
} catch (Exception e) {
e.printStackTrace();
System.exit(2);
return;
}
// 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")) {
if (args.length != 2) {
printUsage();
System.exit(1);
}
try {
encryptMessage(args[1]);
} catch (Exception e) {
e.printStackTrace();
System.exit(2);
return;
}
// 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")) {
if (args.length != 2) {
printUsage();
System.exit(1);
}
try {
decryptMessage(args[1]);
} catch (Exception e) {
e.printStackTrace();
System.exit(2);
return;
}
// 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 {
printUsage();
System.exit(1);
}
}
@@ -204,46 +216,6 @@ public class MessageEncrypter {
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 {
String newline = System.getProperty("line.separator");
StringBuilder stringBuilder = new StringBuilder();

View File

@@ -10,8 +10,6 @@ import java.util.logging.Logger;
import javax.inject.Inject;
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 {
@@ -52,11 +50,13 @@ class ScryptKdf implements PasswordBasedKdf {
@Override
public SecretKey deriveKey(String password, byte[] salt, int cost) {
long start = now();
long start = System.currentTimeMillis();
byte[] passwordBytes = StringUtils.toUtf8(password);
SecretKey k = new SecretKey(SCrypt.generate(passwordBytes, salt, cost,
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;
}
}

View File

@@ -16,8 +16,7 @@ import java.util.logging.Logger;
import javax.annotation.concurrent.Immutable;
import static org.briarproject.bramble.util.LogUtils.logDuration;
import static org.briarproject.bramble.util.LogUtils.now;
import static java.util.logging.Level.INFO;
/**
* A key parser that uses the encoding defined in "SEC 1: Elliptic Curve
@@ -49,7 +48,7 @@ class Sec1KeyParser implements KeyParser {
throws GeneralSecurityException {
// 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
long start = now();
long now = System.currentTimeMillis();
if (encodedKey.length != publicKeyBytes)
throw new GeneralSecurityException();
// 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
ECPublicKeyParameters k = new ECPublicKeyParameters(pub, params);
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;
}
@Override
public PrivateKey parsePrivateKey(byte[] encodedKey)
throws GeneralSecurityException {
long start = now();
long now = System.currentTimeMillis();
if (encodedKey.length != privateKeyBytes)
throw new GeneralSecurityException();
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
ECPrivateKeyParameters k = new ECPrivateKeyParameters(d, params);
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;
}
}

View File

@@ -10,37 +10,37 @@ import java.security.GeneralSecurityException;
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;
/**
* @see java.security.Signature#initVerify(java.security.PublicKey)
* @see {@link java.security.Signature#initVerify(java.security.PublicKey)}
*/
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;
/**
* @see java.security.Signature#update(byte[])
* @see {@link java.security.Signature#update(byte[])}
*/
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;
/**
* @see java.security.Signature#sign()}
* @see {@link java.security.Signature#sign()}
*/
byte[] sign() throws GeneralSecurityException;
/**
* @see java.security.Signature#verify(byte[])
* @see {@link java.security.Signature#verify(byte[])}
*/
boolean verify(byte[] signature) throws GeneralSecurityException;
}

View File

@@ -8,7 +8,6 @@ import java.io.InputStream;
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;
@Immutable
@@ -17,13 +16,11 @@ class BdfReaderFactoryImpl implements BdfReaderFactory {
@Override
public BdfReader createReader(InputStream in) {
return new BdfReaderImpl(in, DEFAULT_NESTED_LIMIT,
DEFAULT_MAX_BUFFER_SIZE);
return new BdfReaderImpl(in, DEFAULT_NESTED_LIMIT);
}
@Override
public BdfReader createReader(InputStream in, int nestedLimit,
int maxBufferSize) {
return new BdfReaderImpl(in, nestedLimit, maxBufferSize);
public BdfReader createReader(InputStream in, int nestedLimit) {
return new BdfReaderImpl(in, nestedLimit);
}
}

View File

@@ -37,16 +37,15 @@ class BdfReaderImpl implements BdfReader {
private static final byte[] EMPTY_BUFFER = new byte[0];
private final InputStream in;
private final int nestedLimit, maxBufferSize;
private final int nestedLimit;
private boolean hasLookahead = false, eof = false;
private byte next;
private byte[] buf = new byte[8];
BdfReaderImpl(InputStream in, int nestedLimit, int maxBufferSize) {
BdfReaderImpl(InputStream in, int nestedLimit) {
this.in = in;
this.nestedLimit = nestedLimit;
this.maxBufferSize = maxBufferSize;
}
private void readLookahead() throws IOException {
@@ -92,8 +91,8 @@ class BdfReaderImpl implements BdfReader {
if (hasBoolean()) return readBoolean();
if (hasLong()) return readLong();
if (hasDouble()) return readDouble();
if (hasString()) return readString();
if (hasRaw()) return readRaw();
if (hasString()) return readString(Integer.MAX_VALUE);
if (hasRaw()) return readRaw(Integer.MAX_VALUE);
if (hasList()) return readList(level);
if (hasDictionary()) return readDictionary(level);
throw new FormatException();
@@ -246,11 +245,11 @@ class BdfReaderImpl implements BdfReader {
}
@Override
public String readString() throws IOException {
public String readString(int maxLength) throws IOException {
if (!hasString()) throw new FormatException();
hasLookahead = false;
int length = readStringLength();
if (length < 0 || length > maxBufferSize) throw new FormatException();
if (length < 0 || length > maxLength) throw new FormatException();
if (length == 0) return "";
readIntoBuffer(length);
return new String(buf, 0, length, "UTF-8");
@@ -280,11 +279,11 @@ class BdfReaderImpl implements BdfReader {
}
@Override
public byte[] readRaw() throws IOException {
public byte[] readRaw(int maxLength) throws IOException {
if (!hasRaw()) throw new FormatException();
hasLookahead = false;
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;
byte[] b = new byte[length];
readIntoBuffer(b, length);
@@ -382,7 +381,7 @@ class BdfReaderImpl implements BdfReader {
BdfDictionary dictionary = new BdfDictionary();
readDictionaryStart();
while (!hasDictionaryEnd())
dictionary.put(readString(), readObject(level + 1));
dictionary.put(readString(Integer.MAX_VALUE), readObject(level + 1));
readDictionaryEnd();
return dictionary;
}

View File

@@ -59,8 +59,8 @@ class MetadataParserImpl implements MetadataParser {
if (reader.hasBoolean()) return reader.readBoolean();
if (reader.hasLong()) return reader.readLong();
if (reader.hasDouble()) return reader.readDouble();
if (reader.hasString()) return reader.readString();
if (reader.hasRaw()) return reader.readRaw();
if (reader.hasString()) return reader.readString(Integer.MAX_VALUE);
if (reader.hasRaw()) return reader.readRaw(Integer.MAX_VALUE);
if (reader.hasList()) return reader.readList();
if (reader.hasDictionary()) return reader.readDictionary();
throw new FormatException();

View File

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

View File

@@ -68,15 +68,13 @@ import javax.annotation.Nullable;
import javax.annotation.concurrent.ThreadSafe;
import javax.inject.Inject;
import static java.util.logging.Level.FINE;
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.SHARED;
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.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
@NotNullByDefault
@@ -110,7 +108,7 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
try {
close();
} catch (DbException e) {
logException(LOG, WARNING, e);
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
}
});
return reopened;
@@ -127,13 +125,13 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
// Don't allow reentrant locking
if (lock.getReadHoldCount() > 0) throw new IllegalStateException();
if (lock.getWriteHoldCount() > 0) throw new IllegalStateException();
long start = now();
if (readOnly) {
lock.readLock().lock();
logDuration(LOG, "Waiting for read lock", start);
} else {
lock.writeLock().lock();
logDuration(LOG, "Waiting for write lock", start);
long start = System.currentTimeMillis();
if (readOnly) lock.readLock().lock();
else lock.writeLock().lock();
if (LOG.isLoggable(FINE)) {
long duration = System.currentTimeMillis() - start;
if (readOnly) LOG.fine("Waited " + duration + " ms for read lock");
else LOG.fine("Waited " + duration + " ms for write lock");
}
try {
return new Transaction(db.startTransaction(), readOnly);
@@ -236,17 +234,29 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
}
@Override
public KeySetId addTransportKeys(Transaction transaction, ContactId c,
TransportKeys k) throws DbException {
public KeySetId addTransportKeys(Transaction transaction,
@Nullable ContactId c, TransportKeys k) throws DbException {
if (transaction.isReadOnly()) throw new IllegalArgumentException();
T txn = unbox(transaction);
if (!db.containsContact(txn, c))
if (c != null && !db.containsContact(txn, c))
throw new NoSuchContactException();
if (!db.containsTransport(txn, k.getTransportId()))
throw new NoSuchTransportException();
return db.addTransportKeys(txn, c, k);
}
@Override
public void bindTransportKeys(Transaction transaction, ContactId c,
TransportId t, KeySetId k) throws DbException {
if (transaction.isReadOnly()) throw new IllegalArgumentException();
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
public boolean containsContact(Transaction transaction, AuthorId remote,
AuthorId local) throws DbException {

View File

@@ -53,7 +53,6 @@ import java.util.logging.Logger;
import javax.annotation.Nullable;
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.WARNING;
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.SCHEMA_VERSION_KEY;
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
@@ -76,7 +74,7 @@ import static org.briarproject.bramble.util.LogUtils.logException;
abstract class JdbcDatabase implements Database<Connection> {
// 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
private static final int OFFSET_PREV = -1;
@@ -238,7 +236,7 @@ abstract class JdbcDatabase implements Database<Connection> {
+ " (transportId _STRING NOT NULL,"
+ " keySetId _COUNTER,"
+ " rotationPeriod BIGINT NOT NULL,"
+ " contactId INT NOT NULL,"
+ " contactId INT," // Null if keys are not bound
+ " tagKey _SECRET NOT NULL,"
+ " headerKey _SECRET NOT NULL,"
+ " stream BIGINT NOT NULL,"
@@ -257,7 +255,7 @@ abstract class JdbcDatabase implements Database<Connection> {
+ " (transportId _STRING NOT NULL,"
+ " keySetId INT NOT NULL,"
+ " rotationPeriod BIGINT NOT NULL,"
+ " contactId INT NOT NULL,"
+ " contactId INT," // Null if keys are not bound
+ " tagKey _SECRET NOT NULL,"
+ " headerKey _SECRET NOT NULL,"
+ " base BIGINT NOT NULL,"
@@ -391,7 +389,7 @@ abstract class JdbcDatabase implements Database<Connection> {
// Package access for testing
List<Migration<Connection>> getMigrations() {
return singletonList(new Migration38_39());
return Collections.emptyList();
}
private void storeSchemaVersion(Connection txn, int version)
@@ -405,7 +403,7 @@ abstract class JdbcDatabase implements Database<Connection> {
try {
if (rs != null) rs.close();
} 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 {
if (s != null) s.close();
} 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) {
// Try to close the connection
logException(LOG, WARNING, e);
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
try {
txn.close();
} catch (SQLException e1) {
logException(LOG, WARNING, e1);
if (LOG.isLoggable(WARNING))
LOG.log(WARNING, e1.toString(), e1);
}
// Whatever happens, allow the database to close
connectionsLock.lock();
@@ -884,7 +883,7 @@ abstract class JdbcDatabase implements Database<Connection> {
}
@Override
public KeySetId addTransportKeys(Connection txn, ContactId c,
public KeySetId addTransportKeys(Connection txn, @Nullable ContactId c,
TransportKeys k) throws DbException {
PreparedStatement ps = null;
ResultSet rs = null;
@@ -894,7 +893,8 @@ abstract class JdbcDatabase implements Database<Connection> {
+ " rotationPeriod, tagKey, headerKey, stream, active)"
+ " VALUES (?, ?, ?, ?, ?, ?, ?)";
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());
OutgoingKeys outCurr = k.getCurrentOutgoingKeys();
ps.setLong(3, outCurr.getRotationPeriod());
@@ -922,7 +922,8 @@ abstract class JdbcDatabase implements Database<Connection> {
+ " VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)";
ps = txn.prepareStatement(sql);
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());
// Previous rotation period
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
public boolean containsContact(Connection txn, AuthorId remote,
AuthorId local) throws DbException {
@@ -2144,6 +2172,7 @@ abstract class JdbcDatabase implements Database<Connection> {
if (inKeys.size() < (i + 1) * 3) throw new DbStateException();
KeySetId keySetId = new KeySetId(rs.getInt(1));
ContactId contactId = new ContactId(rs.getInt(2));
if (rs.wasNull()) contactId = null;
long rotationPeriod = rs.getLong(3);
SecretKey tagKey = new SecretKey(rs.getBytes(4));
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.WARNING;
import static org.briarproject.bramble.api.keyagreement.KeyAgreementConstants.CONNECTION_TIMEOUT;
import static org.briarproject.bramble.util.LogUtils.logException;
@NotNullByDefault
class KeyAgreementConnector {
@@ -135,7 +134,7 @@ class KeyAgreementConnector {
Thread.currentThread().interrupt();
return null;
} catch (IOException e) {
logException(LOG, WARNING, e);
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
return null;
} finally {
stopListening();

View File

@@ -28,7 +28,6 @@ import java.util.logging.Logger;
import javax.inject.Inject;
import static java.util.logging.Level.WARNING;
import static org.briarproject.bramble.util.LogUtils.logException;
@MethodsNotNullByDefault
@ParametersNotNullByDefault
@@ -121,11 +120,13 @@ class KeyAgreementTaskImpl extends Thread implements KeyAgreementTask,
// Broadcast result to caller
eventBus.broadcast(new KeyAgreementFinishedEvent(result));
} catch (AbortException e) {
logException(LOG, WARNING, e);
if (LOG.isLoggable(WARNING))
LOG.log(WARNING, e.toString(), e);
// Notify caller that the protocol was aborted
eventBus.broadcast(new KeyAgreementAbortedEvent(e.receivedAbort));
} catch (IOException e) {
logException(LOG, WARNING, e);
if (LOG.isLoggable(WARNING))
LOG.log(WARNING, e.toString(), e);
// Notify caller that the connection failed
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.CONFIRM;
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.
@@ -73,7 +72,7 @@ class KeyAgreementTransport {
try {
writeRecord(ABORT, new byte[0]);
} catch (IOException e) {
logException(LOG, WARNING, e);
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
exception = true;
}
tryToClose(exception);
@@ -84,7 +83,7 @@ class KeyAgreementTransport {
kac.getConnection().getReader().dispose(exception, true);
kac.getConnection().getWriter().dispose(exception);
} 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.inject.Inject;
import static java.util.logging.Level.FINE;
import static java.util.logging.Level.INFO;
import static java.util.logging.Level.WARNING;
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.SERVICE_ERROR;
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
@NotNullByDefault
@@ -105,20 +101,24 @@ class LifecycleManagerImpl implements LifecycleManager, MigrationListener {
}
private LocalAuthor createLocalAuthor(String nickname) {
long start = now();
long now = System.currentTimeMillis();
KeyPair keyPair = crypto.generateSignatureKeyPair();
byte[] publicKey = keyPair.getPublic().getEncoded();
byte[] privateKey = keyPair.getPrivate().getEncoded();
LocalAuthor localAuthor = authorFactory
.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;
}
private void registerLocalAuthor(LocalAuthor author) throws DbException {
long start = now();
long now = System.currentTimeMillis();
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
@@ -129,11 +129,15 @@ class LifecycleManagerImpl implements LifecycleManager, MigrationListener {
}
try {
LOG.info("Starting services");
long start = now();
long start = System.currentTimeMillis();
boolean reopened = db.open(this);
if (reopened) logDuration(LOG, "Reopening database", start);
else logDuration(LOG, "Creating database", start);
long duration = System.currentTimeMillis() - 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) {
registerLocalAuthor(createLocalAuthor(nickname));
@@ -146,11 +150,13 @@ class LifecycleManagerImpl implements LifecycleManager, MigrationListener {
Transaction txn = db.startTransaction(false);
try {
for (Client c : clients) {
start = now();
start = System.currentTimeMillis();
c.createLocalState(txn);
if (LOG.isLoggable(FINE)) {
logDuration(LOG, "Starting client "
+ c.getClass().getSimpleName(), start);
duration = System.currentTimeMillis() - start;
if (LOG.isLoggable(INFO)) {
LOG.info("Starting client "
+ c.getClass().getSimpleName()
+ " took " + duration + " ms");
}
}
db.commitTransaction(txn);
@@ -158,11 +164,12 @@ class LifecycleManagerImpl implements LifecycleManager, MigrationListener {
db.endTransaction(txn);
}
for (Service s : services) {
start = now();
start = System.currentTimeMillis();
s.startService();
if (LOG.isLoggable(FINE)) {
logDuration(LOG, "Starting service "
+ s.getClass().getSimpleName(), start);
duration = System.currentTimeMillis() - start;
if (LOG.isLoggable(INFO)) {
LOG.info("Starting service " + s.getClass().getSimpleName()
+ " took " + duration + " ms");
}
}
@@ -171,16 +178,16 @@ class LifecycleManagerImpl implements LifecycleManager, MigrationListener {
eventBus.broadcast(new LifecycleEvent(RUNNING));
return SUCCESS;
} catch (DataTooOldException e) {
logException(LOG, WARNING, e);
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
return DATA_TOO_OLD_ERROR;
} catch (DataTooNewException e) {
logException(LOG, WARNING, e);
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
return DATA_TOO_NEW_ERROR;
} catch (DbException e) {
logException(LOG, WARNING, e);
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
return DB_ERROR;
} catch (ServiceException e) {
logException(LOG, WARNING, e);
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
return SERVICE_ERROR;
} finally {
startStopSemaphore.release();
@@ -206,26 +213,29 @@ class LifecycleManagerImpl implements LifecycleManager, MigrationListener {
state = STOPPING;
eventBus.broadcast(new LifecycleEvent(STOPPING));
for (Service s : services) {
long start = now();
long start = System.currentTimeMillis();
s.stopService();
if (LOG.isLoggable(FINE)) {
logDuration(LOG, "Stopping service "
+ s.getClass().getSimpleName(), start);
long duration = System.currentTimeMillis() - start;
if (LOG.isLoggable(INFO)) {
LOG.info("Stopping service " + s.getClass().getSimpleName()
+ " took " + duration + " ms");
}
}
for (ExecutorService e : executors) {
if (LOG.isLoggable(FINE)) {
LOG.fine("Stopping executor "
if (LOG.isLoggable(INFO)) {
LOG.info("Stopping executor "
+ e.getClass().getSimpleName());
}
e.shutdownNow();
}
long start = now();
long start = System.currentTimeMillis();
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();
} catch (DbException | ServiceException e) {
logException(LOG, WARNING, e);
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
} finally {
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.StreamContext;
import org.briarproject.bramble.api.transport.StreamReaderFactory;
import org.briarproject.bramble.api.transport.StreamWriter;
import org.briarproject.bramble.api.transport.StreamWriterFactory;
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.concurrent.Executor;
import java.util.logging.Logger;
@@ -27,7 +27,6 @@ import javax.inject.Inject;
import static java.util.logging.Level.WARNING;
import static org.briarproject.bramble.api.transport.TransportConstants.TAG_LENGTH;
import static org.briarproject.bramble.util.LogUtils.logException;
class ConnectionManagerImpl implements ConnectionManager {
@@ -102,7 +101,7 @@ class ConnectionManagerImpl implements ConnectionManager {
private SyncSession createSimplexOutgoingSession(StreamContext ctx,
TransportConnectionWriter w) throws IOException {
StreamWriter streamWriter = streamWriterFactory.createStreamWriter(
OutputStream streamWriter = streamWriterFactory.createStreamWriter(
w.getOutputStream(), ctx);
return syncSessionFactory.createSimplexOutgoingSession(
ctx.getContactId(), w.getMaxLatency(), streamWriter);
@@ -110,7 +109,7 @@ class ConnectionManagerImpl implements ConnectionManager {
private SyncSession createDuplexOutgoingSession(StreamContext ctx,
TransportConnectionWriter w) throws IOException {
StreamWriter streamWriter = streamWriterFactory.createStreamWriter(
OutputStream streamWriter = streamWriterFactory.createStreamWriter(
w.getOutputStream(), ctx);
return syncSessionFactory.createDuplexOutgoingSession(
ctx.getContactId(), w.getMaxLatency(), w.getMaxIdleTime(),
@@ -136,7 +135,7 @@ class ConnectionManagerImpl implements ConnectionManager {
byte[] tag = readTag(reader);
ctx = keyManager.getStreamContext(transportId, tag);
} catch (IOException | DbException e) {
logException(LOG, WARNING, e);
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
disposeReader(true, false);
return;
}
@@ -152,7 +151,7 @@ class ConnectionManagerImpl implements ConnectionManager {
createIncomingSession(ctx, reader).run();
disposeReader(false, true);
} catch (IOException e) {
logException(LOG, WARNING, e);
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
disposeReader(true, true);
} finally {
connectionRegistry.unregisterConnection(contactId, transportId,
@@ -164,7 +163,7 @@ class ConnectionManagerImpl implements ConnectionManager {
try {
reader.dispose(exception, recognised);
} 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 {
ctx = keyManager.getStreamContext(contactId, transportId);
} catch (DbException e) {
logException(LOG, WARNING, e);
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
disposeWriter(true);
return;
}
@@ -205,7 +204,7 @@ class ConnectionManagerImpl implements ConnectionManager {
createSimplexOutgoingSession(ctx, writer).run();
disposeWriter(false);
} catch (IOException e) {
logException(LOG, WARNING, e);
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
disposeWriter(true);
} finally {
connectionRegistry.unregisterConnection(contactId, transportId,
@@ -217,7 +216,7 @@ class ConnectionManagerImpl implements ConnectionManager {
try {
writer.dispose(exception);
} 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);
ctx = keyManager.getStreamContext(transportId, tag);
} catch (IOException | DbException e) {
logException(LOG, WARNING, e);
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
disposeReader(true, false);
return;
}
@@ -266,7 +265,7 @@ class ConnectionManagerImpl implements ConnectionManager {
incomingSession.run();
disposeReader(false, true);
} catch (IOException e) {
logException(LOG, WARNING, e);
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
disposeReader(true, true);
} finally {
connectionRegistry.unregisterConnection(contactId, transportId,
@@ -280,7 +279,7 @@ class ConnectionManagerImpl implements ConnectionManager {
try {
ctx = keyManager.getStreamContext(contactId, transportId);
} catch (DbException e) {
logException(LOG, WARNING, e);
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
disposeWriter(true);
return;
}
@@ -295,30 +294,28 @@ class ConnectionManagerImpl implements ConnectionManager {
outgoingSession.run();
disposeWriter(false);
} catch (IOException e) {
logException(LOG, WARNING, e);
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
disposeWriter(true);
}
}
private void disposeReader(boolean exception, boolean recognised) {
// Interrupt the outgoing session so it finishes cleanly
if (outgoingSession != null) outgoingSession.interrupt();
if (exception && outgoingSession != null)
outgoingSession.interrupt();
try {
reader.dispose(exception, recognised);
} catch (IOException e) {
logException(LOG, WARNING, e);
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
}
}
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)
incomingSession.interrupt();
try {
writer.dispose(exception);
} 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 {
ctx = keyManager.getStreamContext(contactId, transportId);
} catch (DbException e) {
logException(LOG, WARNING, e);
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
disposeWriter(true);
return;
}
@@ -365,7 +362,7 @@ class ConnectionManagerImpl implements ConnectionManager {
outgoingSession.run();
disposeWriter(false);
} catch (IOException e) {
logException(LOG, WARNING, e);
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
disposeWriter(true);
}
}
@@ -377,7 +374,7 @@ class ConnectionManagerImpl implements ConnectionManager {
byte[] tag = readTag(reader);
ctx = keyManager.getStreamContext(transportId, tag);
} catch (IOException | DbException e) {
logException(LOG, WARNING, e);
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
disposeReader(true, false);
return;
}
@@ -401,7 +398,7 @@ class ConnectionManagerImpl implements ConnectionManager {
incomingSession.run();
disposeReader(false, true);
} catch (IOException e) {
logException(LOG, WARNING, e);
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
disposeReader(true, true);
} finally {
connectionRegistry.unregisterConnection(contactId, transportId,
@@ -410,24 +407,22 @@ class ConnectionManagerImpl implements ConnectionManager {
}
private void disposeReader(boolean exception, boolean recognised) {
// Interrupt the outgoing session so it finishes cleanly
if (outgoingSession != null) outgoingSession.interrupt();
if (exception && outgoingSession != null)
outgoingSession.interrupt();
try {
reader.dispose(exception, recognised);
} catch (IOException e) {
logException(LOG, WARNING, e);
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
}
}
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)
incomingSession.interrupt();
try {
writer.dispose(exception);
} 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();
List<ContactId> ids = new ArrayList<>(m.keySet());
if (LOG.isLoggable(INFO))
LOG.info(ids.size() + " contacts connected: " + t);
LOG.info(ids.size() + " contacts connected");
return ids;
} finally {
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.nullsafety.NotNullByDefault;
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.PluginCallback;
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.settings.Settings;
import org.briarproject.bramble.api.settings.SettingsManager;
import org.briarproject.bramble.api.system.Clock;
import org.briarproject.bramble.api.system.Scheduler;
import org.briarproject.bramble.api.ui.UiCallback;
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.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.logging.Logger;
import javax.annotation.concurrent.ThreadSafe;
import javax.inject.Inject;
import static java.util.logging.Level.FINE;
import static java.util.logging.Level.INFO;
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
@NotNullByDefault
@@ -64,15 +57,12 @@ class PluginManagerImpl implements PluginManager, Service {
Logger.getLogger(PluginManagerImpl.class.getName());
private final Executor ioExecutor;
private final ScheduledExecutorService scheduler;
private final EventBus eventBus;
private final PluginConfig pluginConfig;
private final ConnectionManager connectionManager;
private final ConnectionRegistry connectionRegistry;
private final SettingsManager settingsManager;
private final TransportPropertyManager transportPropertyManager;
private final SecureRandom random;
private final Clock clock;
private final UiCallback uiCallback;
private final Map<TransportId, Plugin> plugins;
private final List<SimplexPlugin> simplexPlugins;
private final List<DuplexPlugin> duplexPlugins;
@@ -80,41 +70,27 @@ class PluginManagerImpl implements PluginManager, Service {
private final AtomicBoolean used = new AtomicBoolean(false);
@Inject
PluginManagerImpl(@IoExecutor Executor ioExecutor,
@Scheduler ScheduledExecutorService scheduler, EventBus eventBus,
PluginManagerImpl(@IoExecutor Executor ioExecutor, EventBus eventBus,
PluginConfig pluginConfig, ConnectionManager connectionManager,
ConnectionRegistry connectionRegistry,
SettingsManager settingsManager,
TransportPropertyManager transportPropertyManager,
SecureRandom random, Clock clock) {
UiCallback uiCallback) {
this.ioExecutor = ioExecutor;
this.scheduler = scheduler;
this.eventBus = eventBus;
this.pluginConfig = pluginConfig;
this.connectionManager = connectionManager;
this.connectionRegistry = connectionRegistry;
this.settingsManager = settingsManager;
this.transportPropertyManager = transportPropertyManager;
this.random = random;
this.clock = clock;
this.uiCallback = uiCallback;
plugins = new ConcurrentHashMap<>();
simplexPlugins = new CopyOnWriteArrayList<>();
duplexPlugins = new CopyOnWriteArrayList<>();
startLatches = new ConcurrentHashMap<>();
}
@Override
public void startService() {
public void startService() throws ServiceException {
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
LOG.info("Starting simplex plugins");
for (SimplexPluginFactory f : pluginConfig.getSimplexFactories()) {
@@ -209,16 +185,17 @@ class PluginManagerImpl implements PluginManager, Service {
@Override
public void run() {
try {
long start = now();
long start = System.currentTimeMillis();
plugin.start();
if (LOG.isLoggable(FINE)) {
logDuration(LOG, "Starting plugin " + plugin.getId(),
start);
long duration = System.currentTimeMillis() - start;
if (LOG.isLoggable(INFO)) {
LOG.info("Starting plugin " + plugin.getId() + " took " +
duration + " ms");
}
} catch (PluginException e) {
if (LOG.isLoggable(WARNING)) {
LOG.warning("Plugin " + plugin.getId() + " did not start");
logException(LOG, WARNING, e);
LOG.log(WARNING, e.toString(), e);
}
} finally {
startLatch.countDown();
@@ -246,11 +223,12 @@ class PluginManagerImpl implements PluginManager, Service {
// Wait for the plugin to finish starting
startLatch.await();
// Stop the plugin
long start = now();
long start = System.currentTimeMillis();
plugin.stop();
if (LOG.isLoggable(FINE)) {
logDuration(LOG, "Stopping plugin " + plugin.getId(),
start);
long duration = System.currentTimeMillis() - start;
if (LOG.isLoggable(INFO)) {
LOG.info("Stopping plugin " + plugin.getId()
+ " took " + duration + " ms");
}
} catch (InterruptedException e) {
LOG.warning("Interrupted while waiting for plugin to stop");
@@ -258,7 +236,7 @@ class PluginManagerImpl implements PluginManager, Service {
} catch (PluginException e) {
if (LOG.isLoggable(WARNING)) {
LOG.warning("Plugin " + plugin.getId() + " did not stop");
logException(LOG, WARNING, e);
LOG.log(WARNING, e.toString(), e);
}
} finally {
stopLatch.countDown();
@@ -280,7 +258,7 @@ class PluginManagerImpl implements PluginManager, Service {
try {
return settingsManager.getSettings(id.getString());
} catch (DbException e) {
logException(LOG, WARNING, e);
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
return new Settings();
}
}
@@ -290,7 +268,27 @@ class PluginManagerImpl implements PluginManager, Service {
try {
return transportPropertyManager.getLocalProperties(id);
} 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();
}
}
@@ -300,7 +298,7 @@ class PluginManagerImpl implements PluginManager, Service {
try {
settingsManager.mergeSettings(s, id.getString());
} 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 {
transportPropertyManager.mergeLocalProperties(id, p);
} 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
public void transportEnabled() {
eventBus.broadcast(new TransportEnabledEvent(id));

View File

@@ -1,10 +1,18 @@
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.plugin.BackoffFactory;
import org.briarproject.bramble.api.plugin.ConnectionManager;
import org.briarproject.bramble.api.plugin.ConnectionRegistry;
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.Singleton;
@@ -18,6 +26,8 @@ public class PluginModule {
public static class EagerSingletons {
@Inject
PluginManager pluginManager;
@Inject
Poller poller;
}
@Provides
@@ -25,6 +35,19 @@ public class PluginModule {
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
@Singleton
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.event.ContactStatusChangedEvent;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.event.Event;
import org.briarproject.bramble.api.event.EventListener;
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.TransportEnabledEvent;
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.Scheduler;
import java.security.SecureRandom;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Executor;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledExecutorService;
@@ -37,11 +35,10 @@ import java.util.concurrent.locks.ReentrantLock;
import java.util.logging.Logger;
import javax.annotation.concurrent.ThreadSafe;
import javax.inject.Inject;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static java.util.logging.Level.INFO;
import static java.util.logging.Level.WARNING;
import static org.briarproject.bramble.util.LogUtils.logException;
@ThreadSafe
@NotNullByDefault
@@ -54,38 +51,40 @@ class Poller implements EventListener {
private final ConnectionManager connectionManager;
private final ConnectionRegistry connectionRegistry;
private final PluginManager pluginManager;
private final TransportPropertyManager transportPropertyManager;
private final SecureRandom random;
private final Clock clock;
private final Lock lock;
private final Map<TransportId, ScheduledPollTask> tasks; // Locking: lock
private final Set<TransportId> polling; // Locking: lock
@Inject
Poller(@IoExecutor Executor ioExecutor,
@Scheduler ScheduledExecutorService scheduler,
ConnectionManager connectionManager,
ConnectionRegistry connectionRegistry, PluginManager pluginManager,
TransportPropertyManager transportPropertyManager,
SecureRandom random, Clock clock) {
this.ioExecutor = ioExecutor;
this.scheduler = scheduler;
this.connectionManager = connectionManager;
this.connectionRegistry = connectionRegistry;
this.pluginManager = pluginManager;
this.transportPropertyManager = transportPropertyManager;
this.random = random;
this.clock = clock;
lock = new ReentrantLock();
tasks = new HashMap<>();
polling = new HashSet<>();
}
@Override
public void eventOccurred(Event e) {
if (e instanceof ContactStatusChangedEvent) {
ContactStatusChangedEvent c = (ContactStatusChangedEvent) e;
/*
if (c.isActive()) {
// Connect to the newly activated contact
connectToContact(c.getContactId());
}
*/
} else if (e instanceof ConnectionClosedEvent) {
ConnectionClosedEvent c = (ConnectionClosedEvent) e;
// Reschedule polling, the polling interval may have decreased
@@ -127,15 +126,10 @@ class Poller implements EventListener {
private void connectToContact(ContactId c, SimplexPlugin p) {
ioExecutor.execute(() -> {
TransportId t = p.getId();
if (connectionRegistry.isConnected(c, t)) return;
try {
TransportProperties props =
transportPropertyManager.getRemoteProperties(c, t);
TransportConnectionWriter w = p.createWriter(props);
if (!connectionRegistry.isConnected(c, t)) {
TransportConnectionWriter w = p.createWriter(c);
if (w != null)
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) {
ioExecutor.execute(() -> {
TransportId t = p.getId();
if (connectionRegistry.isConnected(c, t)) return;
try {
TransportProperties props =
transportPropertyManager.getRemoteProperties(c, t);
DuplexTransportConnection d = p.createConnection(props);
if (!connectionRegistry.isConnected(c, t)) {
DuplexTransportConnection d = p.createConnection(c);
if (d != null)
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) {
TransportId t = p.getId();
if (LOG.isLoggable(INFO)) LOG.info("Polling plugin " + t);
try {
Map<ContactId, TransportProperties> remote =
transportPropertyManager.getRemoteProperties(t);
Collection<ContactId> connected =
connectionRegistry.getConnectedContacts(t);
remote = new HashMap<>(remote);
remote.keySet().removeAll(connected);
if (!remote.isEmpty()) p.poll(remote);
} catch (DbException e) {
logException(LOG, WARNING, e);
}
p.poll(connectionRegistry.getConnectedContacts(t));
}
private class ScheduledPollTask {
@@ -242,20 +221,33 @@ class Poller implements EventListener {
@Override
@IoExecutor
public void run() {
TransportId t = plugin.getId();
boolean shouldPoll;
lock.lock();
try {
TransportId t = plugin.getId();
ScheduledPollTask scheduled = tasks.get(t);
if (scheduled != null && scheduled.task != this)
return; // Replaced by another task
tasks.remove(t);
// Don't poll again if last poll is still running
shouldPoll = polling.add(t);
} finally {
lock.unlock();
}
int delay = plugin.getPollingInterval();
if (randomiseNext) delay = (int) (delay * random.nextDouble());
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.WARNING;
import static org.briarproject.bramble.util.LogUtils.logException;
@NotNullByDefault
@ThreadSafe
@@ -93,7 +92,7 @@ class BluetoothConnectionLimiterImpl implements BluetoothConnectionLimiter {
conn.getWriter().dispose(false);
conn.getReader().dispose(false, false);
} 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.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.Entry;
import java.util.UUID;
import java.util.concurrent.Executor;
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_UUID;
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;
@MethodsNotNullByDefault
@@ -53,6 +55,12 @@ abstract class BluetoothPlugin<SS> implements DuplexPlugin, EventListener {
private static final Logger LOG =
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;
private final Executor ioExecutor;
@@ -170,7 +178,7 @@ abstract class BluetoothPlugin<SS> implements DuplexPlugin, EventListener {
try {
ss = openServerSocket(contactConnectionsUuid);
} catch (IOException e) {
logException(LOG, WARNING, e);
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
return;
}
if (!isRunning() || !shouldAllowContactConnections()) {
@@ -250,27 +258,45 @@ abstract class BluetoothPlugin<SS> implements DuplexPlugin, EventListener {
}
@Override
public void poll(Map<ContactId, TransportProperties> contacts) {
public void poll(Collection<ContactId> connected) {
if (!isRunning() || !shouldAllowContactConnections()) return;
backoff.increment();
// Try to connect to known devices in parallel
for (Entry<ContactId, TransportProperties> e : contacts.entrySet()) {
String address = e.getValue().get(PROP_ADDRESS);
if (StringUtils.isNullOrEmpty(address)) continue;
String uuid = e.getValue().get(PROP_UUID);
if (StringUtils.isNullOrEmpty(uuid)) continue;
ContactId c = e.getKey();
ioExecutor.execute(() -> {
// Try to connect to known devices in a random order
Map<ContactId, TransportProperties> remote =
callback.getRemoteProperties();
List<ContactId> keys = new ArrayList<>(remote.keySet());
Collections.shuffle(keys);
ioExecutor.execute(() -> {
boolean first = true;
for (ContactId c : keys) {
if (!isRunning() || !shouldAllowContactConnections()) 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);
if (conn != null) {
backoff.reset();
if (connectionLimiter.contactConnectionOpened(conn))
callback.outgoingConnectionCreated(c, conn);
}
});
}
}
});
}
@Nullable
@@ -305,9 +331,10 @@ abstract class BluetoothPlugin<SS> implements DuplexPlugin, EventListener {
}
@Override
public DuplexTransportConnection createConnection(TransportProperties p) {
public DuplexTransportConnection createConnection(ContactId c) {
if (!isRunning() || !shouldAllowContactConnections()) return null;
if (!connectionLimiter.canOpenContactConnection()) return null;
TransportProperties p = callback.getRemoteProperties(c);
String address = p.get(PROP_ADDRESS);
if (StringUtils.isNullOrEmpty(address)) return null;
String uuid = p.get(PROP_UUID);
@@ -337,7 +364,7 @@ abstract class BluetoothPlugin<SS> implements DuplexPlugin, EventListener {
try {
ss = openServerSocket(uuid);
} catch (IOException e) {
logException(LOG, WARNING, e);
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
return null;
}
if (!isRunning()) {

View File

@@ -1,22 +1,27 @@
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.plugin.TransportConnectionReader;
import org.briarproject.bramble.api.plugin.TransportConnectionWriter;
import org.briarproject.bramble.api.plugin.simplex.SimplexPlugin;
import org.briarproject.bramble.api.plugin.simplex.SimplexPluginCallback;
import org.briarproject.bramble.api.properties.TransportProperties;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
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 javax.annotation.Nullable;
import static java.util.logging.Level.WARNING;
import static org.briarproject.bramble.api.plugin.FileConstants.PROP_PATH;
import static org.briarproject.bramble.util.LogUtils.logException;
import static org.briarproject.bramble.util.StringUtils.isNullOrEmpty;
import static org.briarproject.bramble.api.transport.TransportConstants.MIN_STREAM_LENGTH;
@NotNullByDefault
abstract class FilePlugin implements SimplexPlugin {
@@ -24,15 +29,25 @@ abstract class FilePlugin implements SimplexPlugin {
private static final Logger LOG =
Logger.getLogger(FilePlugin.class.getName());
protected final Executor ioExecutor;
protected final SimplexPluginCallback callback;
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,
boolean recognised);
@Nullable
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.maxLatency = maxLatency;
}
@@ -43,36 +58,81 @@ abstract class FilePlugin implements SimplexPlugin {
}
@Override
public TransportConnectionReader createReader(TransportProperties p) {
if (!isRunning()) return null;
String path = p.get(PROP_PATH);
if (isNullOrEmpty(path)) return null;
public int getMaxIdleTime() {
return Integer.MAX_VALUE; // We don't need keepalives
}
@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 {
File file = new File(path);
FileInputStream in = new FileInputStream(file);
return new FileTransportReader(file, in, this);
long capacity = dir.getFreeSpace();
if (capacity < MIN_STREAM_LENGTH) return null;
OutputStream out = new FileOutputStream(f);
return new FileTransportWriter(f, out, capacity, this);
} catch (IOException e) {
logException(LOG, WARNING, e);
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
f.delete();
return null;
}
}
@Override
public TransportConnectionWriter createWriter(TransportProperties p) {
if (!isRunning()) return null;
String path = p.get(PROP_PATH);
if (isNullOrEmpty(path)) return null;
try {
File file = new File(path);
if (!file.exists() && !file.createNewFile()) {
LOG.info("Failed to create file");
return null;
protected void createReaderFromFile(File f) {
if (!running) return;
ioExecutor.execute(new ReaderCreator(f));
}
private class ReaderCreator implements Runnable {
private final File file;
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 static java.util.logging.Level.WARNING;
import static org.briarproject.bramble.util.LogUtils.logException;
@NotNullByDefault
class FileTransportReader implements TransportConnectionReader {
@@ -37,8 +36,11 @@ class FileTransportReader implements TransportConnectionReader {
try {
in.close();
} 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 static java.util.logging.Level.WARNING;
import static org.briarproject.bramble.util.LogUtils.logException;
@NotNullByDefault
class FileTransportWriter implements TransportConnectionWriter {
@@ -19,11 +18,14 @@ class FileTransportWriter implements TransportConnectionWriter {
private final File file;
private final OutputStream out;
private final long capacity;
private final FilePlugin plugin;
FileTransportWriter(File file, OutputStream out, FilePlugin plugin) {
FileTransportWriter(File file, OutputStream out, long capacity,
FilePlugin plugin) {
this.file = file;
this.out = out;
this.capacity = capacity;
this.plugin = plugin;
}
@@ -37,6 +39,11 @@ class FileTransportWriter implements TransportConnectionWriter {
return plugin.getMaxIdleTime();
}
@Override
public long getCapacity() {
return capacity;
}
@Override
public OutputStream getOutputStream() {
return out;
@@ -47,8 +54,9 @@ class FileTransportWriter implements TransportConnectionWriter {
try {
out.close();
} 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.PROP_IP_PORTS;
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;
@NotNullByDefault
@@ -296,7 +295,7 @@ class LanTcpPlugin extends TcpPlugin {
try {
ss.close();
} 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.WARNING;
import static org.briarproject.bramble.util.LogUtils.logException;
import static org.briarproject.bramble.util.PrivacyUtils.scrubInetAddress;
@ThreadSafe
@@ -60,7 +59,7 @@ class PortMapperImpl implements PortMapper {
if (externalString != null)
external = InetAddress.getByName(externalString);
} 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);
}
@@ -77,7 +76,7 @@ class PortMapperImpl implements PortMapper {
try {
d.discover();
} catch (IOException | SAXException | ParserConfigurationException e) {
logException(LOG, WARNING, e);
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
}
gateway = d.getValidGateway();
}
@@ -88,7 +87,7 @@ class PortMapperImpl implements PortMapper {
if (LOG.isLoggable(INFO))
LOG.info("Deleted mapping for port " + port);
} 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.WARNING;
import static org.briarproject.bramble.util.LogUtils.logException;
import static org.briarproject.bramble.util.PrivacyUtils.scrubSocketAddress;
@MethodsNotNullByDefault
@@ -153,7 +152,7 @@ abstract class TcpPlugin implements DuplexPlugin {
try {
if (ss != null) ss.close();
} catch (IOException e) {
logException(LOG, WARNING, e);
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
} finally {
callback.transportDisabled();
}
@@ -208,16 +207,20 @@ abstract class TcpPlugin implements DuplexPlugin {
}
@Override
public void poll(Map<ContactId, TransportProperties> contacts) {
public void poll(Collection<ContactId> connected) {
if (!isRunning()) return;
backoff.increment();
for (Entry<ContactId, TransportProperties> e : contacts.entrySet()) {
connectAndCallBack(e.getKey(), e.getValue());
Map<ContactId, TransportProperties> remote =
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) {
ioExecutor.execute(() -> {
if (!isRunning()) return;
DuplexTransportConnection d = createConnection(p);
if (d != null) {
backoff.reset();
@@ -227,8 +230,13 @@ abstract class TcpPlugin implements DuplexPlugin {
}
@Override
public DuplexTransportConnection createConnection(TransportProperties p) {
public DuplexTransportConnection createConnection(ContactId c) {
if (!isRunning()) return null;
return createConnection(callback.getRemoteProperties(c));
}
@Nullable
private DuplexTransportConnection createConnection(TransportProperties p) {
for (InetSocketAddress remote : getRemoteSocketAddresses(p)) {
if (!isConnectable(remote)) {
if (LOG.isLoggable(INFO)) {
@@ -307,7 +315,7 @@ abstract class TcpPlugin implements DuplexPlugin {
try {
ifaces = Collections.list(NetworkInterface.getNetworkInterfaces());
} catch (SocketException e) {
logException(LOG, WARNING, e);
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
return Collections.emptyList();
}
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.logging.Level.WARNING;
import static org.briarproject.bramble.util.LogUtils.logException;
@MethodsNotNullByDefault
@ParametersNotNullByDefault
@@ -79,7 +78,7 @@ class ReliabilityLayerImpl implements ReliabilityLayer, WriteHandler {
Thread.currentThread().interrupt();
running = false;
} catch (IOException e) {
logException(LOG, WARNING, e);
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
running = false;
}
});

View File

@@ -1,12 +1,7 @@
package org.briarproject.bramble.reporting;
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.plugin.TorConstants;
import org.briarproject.bramble.api.plugin.event.TransportEnabledEvent;
import org.briarproject.bramble.api.reporting.DevConfig;
import org.briarproject.bramble.api.reporting.DevReporter;
import org.briarproject.bramble.util.IoUtils;
@@ -23,20 +18,17 @@ import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.concurrent.Executor;
import java.util.logging.Logger;
import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable;
import javax.inject.Inject;
import javax.net.SocketFactory;
import static java.util.logging.Level.WARNING;
import static org.briarproject.bramble.util.LogUtils.logException;
@Immutable
@NotNullByDefault
class DevReporterImpl implements DevReporter, EventListener {
class DevReporterImpl implements DevReporter {
private static final Logger LOG =
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 LINE_LENGTH = 70;
private final Executor ioExecutor;
private final CryptoComponent crypto;
private final DevConfig devConfig;
private final SocketFactory torSocketFactory;
@Inject
DevReporterImpl(@IoExecutor Executor ioExecutor, CryptoComponent crypto,
DevConfig devConfig, SocketFactory torSocketFactory) {
this.ioExecutor = ioExecutor;
DevReporterImpl(CryptoComponent crypto, DevConfig devConfig,
SocketFactory torSocketFactory) {
this.crypto = crypto;
this.devConfig = devConfig;
this.torSocketFactory = torSocketFactory;
@@ -74,7 +63,6 @@ class DevReporterImpl implements DevReporter, EventListener {
@Override
public void encryptReportToFile(File reportDir, String filename,
String report) throws FileNotFoundException {
LOG.info("Encrypting report to file");
byte[] plaintext = StringUtils.toUtf8(report);
byte[] ciphertext = crypto.encryptToKey(devConfig.getDevPublicKey(),
plaintext);
@@ -94,17 +82,7 @@ class DevReporterImpl implements DevReporter, EventListener {
}
@Override
public void eventOccurred(Event e) {
if (e instanceof TransportEnabledEvent) {
TransportEnabledEvent t = (TransportEnabledEvent) e;
if (t.getTransportId().equals(TorConstants.ID))
ioExecutor.execute(this::sendReports);
}
}
@Override
public void sendReports() {
File reportDir = devConfig.getReportDir();
public void sendReports(File reportDir) {
File[] reports = reportDir.listFiles();
if (reports == null || reports.length == 0)
return; // No reports to send
@@ -133,7 +111,7 @@ class DevReporterImpl implements DevReporter, EventListener {
try {
if (c != null) c.close();
} 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 {
if (s != null) s.close();
} 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;
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 javax.inject.Inject;
import javax.inject.Singleton;
import javax.net.SocketFactory;
import dagger.Module;
import dagger.Provides;
@@ -12,16 +12,9 @@ import dagger.Provides;
@Module
public class ReportingModule {
public static class EagerSingletons {
@Inject
DevReporter devReporter;
}
@Provides
@Singleton
DevReporter provideDevReporter(DevReporterImpl devReporter,
EventBus eventBus) {
eventBus.addListener(devReporter);
return devReporter;
DevReporter provideDevReporter(CryptoComponent crypto,
DevConfig devConfig, SocketFactory torSocketFactory) {
return new DevReporterImpl(crypto, devConfig, torSocketFactory);
}
}

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.MessageToRequestEvent;
import org.briarproject.bramble.api.system.Clock;
import org.briarproject.bramble.api.transport.StreamWriter;
import java.io.IOException;
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.record.Record.MAX_RECORD_PAYLOAD_BYTES;
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
@@ -69,7 +67,6 @@ class DuplexOutgoingSession implements SyncSession, EventListener {
private final Clock clock;
private final ContactId contactId;
private final int maxLatency, maxIdleTime;
private final StreamWriter streamWriter;
private final SyncRecordWriter recordWriter;
private final BlockingQueue<ThrowingRunnable<IOException>> writerTasks;
@@ -84,8 +81,7 @@ class DuplexOutgoingSession implements SyncSession, EventListener {
DuplexOutgoingSession(DatabaseComponent db, Executor dbExecutor,
EventBus eventBus, Clock clock, ContactId contactId, int maxLatency,
int maxIdleTime, StreamWriter streamWriter,
SyncRecordWriter recordWriter) {
int maxIdleTime, SyncRecordWriter recordWriter) {
this.db = db;
this.dbExecutor = dbExecutor;
this.eventBus = eventBus;
@@ -93,7 +89,6 @@ class DuplexOutgoingSession implements SyncSession, EventListener {
this.contactId = contactId;
this.maxLatency = maxLatency;
this.maxIdleTime = maxIdleTime;
this.streamWriter = streamWriter;
this.recordWriter = recordWriter;
writerTasks = new LinkedBlockingQueue<>();
}
@@ -154,7 +149,7 @@ class DuplexOutgoingSession implements SyncSession, EventListener {
dataToFlush = true;
}
}
streamWriter.sendEndOfStream();
if (dataToFlush) recordWriter.flush();
} catch (InterruptedException e) {
LOG.info("Interrupted while waiting for a record to write");
Thread.currentThread().interrupt();
@@ -241,7 +236,7 @@ class DuplexOutgoingSession implements SyncSession, EventListener {
LOG.info("Generated ack: " + (a != null));
if (a != null) writerTasks.add(new WriteAck(a));
} catch (DbException e) {
logException(LOG, WARNING, e);
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
interrupt();
}
}
@@ -288,7 +283,7 @@ class DuplexOutgoingSession implements SyncSession, EventListener {
LOG.info("Generated batch: " + (b != null));
if (b != null) writerTasks.add(new WriteBatch(b));
} catch (DbException e) {
logException(LOG, WARNING, e);
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
interrupt();
}
}
@@ -335,7 +330,7 @@ class DuplexOutgoingSession implements SyncSession, EventListener {
LOG.info("Generated offer: " + (o != null));
if (o != null) writerTasks.add(new WriteOffer(o));
} catch (DbException e) {
logException(LOG, WARNING, e);
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
interrupt();
}
}
@@ -380,7 +375,7 @@ class DuplexOutgoingSession implements SyncSession, EventListener {
LOG.info("Generated request: " + (r != null));
if (r != null) writerTasks.add(new WriteRequest(r));
} catch (DbException e) {
logException(LOG, WARNING, e);
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
interrupt();
}
}

View File

@@ -28,7 +28,6 @@ import javax.annotation.concurrent.ThreadSafe;
import static java.util.logging.Level.WARNING;
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.LifecycleState.STOPPING;
import static org.briarproject.bramble.util.LogUtils.logException;
/**
* An incoming {@link SyncSession}.
@@ -64,11 +63,7 @@ class IncomingSession implements SyncSession, EventListener {
eventBus.addListener(this);
try {
// Read records until interrupted or EOF
while (!interrupted) {
if (recordReader.eof()) {
LOG.info("End of stream");
return;
}
while (!interrupted && !recordReader.eof()) {
if (recordReader.hasAck()) {
Ack a = recordReader.readAck();
dbExecutor.execute(new ReceiveAck(a));
@@ -128,7 +123,7 @@ class IncomingSession implements SyncSession, EventListener {
db.endTransaction(txn);
}
} catch (DbException e) {
logException(LOG, WARNING, e);
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
interrupt();
}
}
@@ -154,7 +149,7 @@ class IncomingSession implements SyncSession, EventListener {
db.endTransaction(txn);
}
} catch (DbException e) {
logException(LOG, WARNING, e);
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
interrupt();
}
}
@@ -180,7 +175,7 @@ class IncomingSession implements SyncSession, EventListener {
db.endTransaction(txn);
}
} catch (DbException e) {
logException(LOG, WARNING, e);
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
interrupt();
}
}
@@ -206,7 +201,7 @@ class IncomingSession implements SyncSession, EventListener {
db.endTransaction(txn);
}
} catch (DbException e) {
logException(LOG, WARNING, e);
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
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.SyncRecordWriter;
import org.briarproject.bramble.api.sync.SyncSession;
import org.briarproject.bramble.api.transport.StreamWriter;
import java.io.IOException;
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.record.Record.MAX_RECORD_PAYLOAD_BYTES;
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
@@ -53,7 +51,6 @@ class SimplexOutgoingSession implements SyncSession, EventListener {
private final EventBus eventBus;
private final ContactId contactId;
private final int maxLatency;
private final StreamWriter streamWriter;
private final SyncRecordWriter recordWriter;
private final AtomicInteger outstandingQueries;
private final BlockingQueue<ThrowingRunnable<IOException>> writerTasks;
@@ -61,14 +58,13 @@ class SimplexOutgoingSession implements SyncSession, EventListener {
private volatile boolean interrupted = false;
SimplexOutgoingSession(DatabaseComponent db, Executor dbExecutor,
EventBus eventBus, ContactId contactId, int maxLatency,
StreamWriter streamWriter, SyncRecordWriter recordWriter) {
EventBus eventBus, ContactId contactId,
int maxLatency, SyncRecordWriter recordWriter) {
this.db = db;
this.dbExecutor = dbExecutor;
this.eventBus = eventBus;
this.contactId = contactId;
this.maxLatency = maxLatency;
this.streamWriter = streamWriter;
this.recordWriter = recordWriter;
outstandingQueries = new AtomicInteger(2); // One per type of record
writerTasks = new LinkedBlockingQueue<>();
@@ -89,7 +85,7 @@ class SimplexOutgoingSession implements SyncSession, EventListener {
if (task == CLOSE) break;
task.run();
}
streamWriter.sendEndOfStream();
recordWriter.flush();
} catch (InterruptedException e) {
LOG.info("Interrupted while waiting for a record to write");
Thread.currentThread().interrupt();
@@ -140,7 +136,7 @@ class SimplexOutgoingSession implements SyncSession, EventListener {
if (a == null) decrementOutstandingQueries();
else writerTasks.add(new WriteAck(a));
} catch (DbException e) {
logException(LOG, WARNING, e);
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
interrupt();
}
}
@@ -185,7 +181,7 @@ class SimplexOutgoingSession implements SyncSession, EventListener {
if (b == null) decrementOutstandingQueries();
else writerTasks.add(new WriteBatch(b));
} catch (DbException e) {
logException(LOG, WARNING, e);
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
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.SyncSessionFactory;
import org.briarproject.bramble.api.system.Clock;
import org.briarproject.bramble.api.transport.StreamWriter;
import java.io.InputStream;
import java.io.OutputStream;
@@ -54,21 +53,19 @@ class SyncSessionFactoryImpl implements SyncSessionFactory {
@Override
public SyncSession createSimplexOutgoingSession(ContactId c,
int maxLatency, StreamWriter streamWriter) {
OutputStream out = streamWriter.getOutputStream();
int maxLatency, OutputStream out) {
SyncRecordWriter recordWriter =
recordWriterFactory.createRecordWriter(out);
return new SimplexOutgoingSession(db, dbExecutor, eventBus, c,
maxLatency, streamWriter, recordWriter);
maxLatency, recordWriter);
}
@Override
public SyncSession createDuplexOutgoingSession(ContactId c, int maxLatency,
int maxIdleTime, StreamWriter streamWriter) {
OutputStream out = streamWriter.getOutputStream();
int maxIdleTime, OutputStream out) {
SyncRecordWriter recordWriter =
recordWriterFactory.createRecordWriter(out);
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.INVALID;
import static org.briarproject.bramble.api.sync.ValidationManager.State.PENDING;
import static org.briarproject.bramble.util.LogUtils.logException;
@ThreadSafe
@NotNullByDefault
@@ -111,7 +110,7 @@ class ValidationManagerImpl implements ValidationManager, Service,
}
validateNextMessageAsync(unvalidated);
} 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");
validateNextMessageAsync(unvalidated);
} 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);
} 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");
deliverNextPendingMessageAsync(pending);
} 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(),
g.getMajorVersion(), context);
} catch (InvalidMessageException e) {
logException(LOG, INFO, e);
if (LOG.isLoggable(INFO))
LOG.log(INFO, e.toString(), e);
Queue<MessageId> invalidate = new LinkedList<>();
invalidate.add(m.getId());
invalidateNextMessageAsync(invalidate);
@@ -326,7 +326,7 @@ class ValidationManagerImpl implements ValidationManager, Service,
} catch (NoSuchGroupException e) {
LOG.info("Group removed during validation");
} 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);
} 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");
shareNextMessageAsync(toShare);
} 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");
invalidateNextMessageAsync(invalidate);
} 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) {
LOG.info("Group removed before validation");
} 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 static java.util.logging.Level.WARNING;
import static org.briarproject.bramble.util.LogUtils.logException;
@Immutable
@NotNullByDefault
@@ -50,7 +49,7 @@ class LinuxSecureRandomProvider extends AbstractSecureRandomProvider {
out.close();
} catch (IOException e) {
// 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 static java.util.logging.Level.WARNING;
import static org.briarproject.bramble.util.LogUtils.logException;
public class LinuxSecureRandomSpi extends SecureRandomSpi {
@@ -40,7 +39,7 @@ public class LinuxSecureRandomSpi extends SecureRandomSpi {
out.close();
} catch (IOException e) {
// 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
public Map<TransportId, KeySetId> addContact(Transaction txn, ContactId c,
SecretKey master, long timestamp, boolean alice, boolean active)
public void addContact(Transaction txn, ContactId c, SecretKey master,
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 {
Map<TransportId, KeySetId> ids = new HashMap<>();
for (Entry<TransportId, TransportKeyManager> e : managers.entrySet()) {
TransportId t = e.getKey();
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;
}
@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
public void activateKeys(Transaction txn, Map<TransportId, KeySetId> keys)
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
public boolean canSendOutgoingStreams(ContactId c, TransportId t) {
TransportKeyManager m = managers.get(t);
return m != null && m.canSendOutgoingStreams(c);
return m == null ? false : m.canSendOutgoingStreams(c);
}
@Override

View File

@@ -3,28 +3,32 @@ package org.briarproject.bramble.transport;
import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.transport.KeySetId;
class MutableKeySet {
import javax.annotation.Nullable;
public class MutableKeySet {
private final KeySetId keySetId;
@Nullable
private final ContactId contactId;
private final MutableTransportKeys transportKeys;
MutableKeySet(KeySetId keySetId, ContactId contactId,
public MutableKeySet(KeySetId keySetId, @Nullable ContactId contactId,
MutableTransportKeys transportKeys) {
this.keySetId = keySetId;
this.contactId = contactId;
this.transportKeys = transportKeys;
}
KeySetId getKeySetId() {
public KeySetId getKeySetId() {
return keySetId;
}
ContactId getContactId() {
@Nullable
public ContactId getContactId() {
return contactId;
}
MutableTransportKeys getTransportKeys() {
public MutableTransportKeys getTransportKeys() {
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.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.transport.StreamContext;
import org.briarproject.bramble.api.transport.StreamWriter;
import org.briarproject.bramble.api.transport.StreamWriterFactory;
import java.io.OutputStream;
@@ -24,14 +23,14 @@ class StreamWriterFactoryImpl implements StreamWriterFactory {
}
@Override
public StreamWriter createStreamWriter(OutputStream out,
public OutputStream createStreamWriter(OutputStream out,
StreamContext ctx) {
return new StreamWriterImpl(
streamEncrypterFactory.createStreamEncrypter(out, ctx));
}
@Override
public StreamWriter createContactExchangeStreamWriter(OutputStream out,
public OutputStream createContactExchangeStreamWriter(OutputStream out,
SecretKey headerKey) {
return new StreamWriterImpl(
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.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.transport.StreamWriter;
import java.io.IOException;
import java.io.OutputStream;
@@ -18,7 +17,7 @@ import static org.briarproject.bramble.api.transport.TransportConstants.MAX_PAYL
*/
@NotThreadSafe
@NotNullByDefault
class StreamWriterImpl extends OutputStream implements StreamWriter {
class StreamWriterImpl extends OutputStream {
private final StreamEncrypter encrypter;
private final byte[] payload;
@@ -30,17 +29,6 @@ class StreamWriterImpl extends OutputStream implements StreamWriter {
payload = new byte[MAX_PAYLOAD_LENGTH];
}
@Override
public OutputStream getOutputStream() {
return this;
}
@Override
public void sendEndOfStream() throws IOException {
writeFrame(true);
encrypter.flush();
}
@Override
public void close() throws IOException {
writeFrame(true);

View File

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

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