Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision
  • 1093-db-compacting
  • 1143-screen-overlay-dialog
  • 1147-bluetooth-discovery
  • 1148-wrong-network-interface
  • 115-tor-performance-measurements
  • 1160-language-setting
  • 1216-fix-testdata
  • 1251-dark-theme
  • 1343-vanniktech-emoji
  • 236-curve25519
  • 278-bqp-ui-part-2
  • 283-bluetooth-zombies
  • 299-bluetooth-remains-active-after-adding-contact
  • 377_replace_data_structures_with_classes
  • 384-conversation-manager
  • 39-keyagreement-wfd
  • 39-keyagreement-wfd-legacy
  • 514-allow-retransmissions-using-lower-latency-transports
  • 541-allow-retransmission-if-faster
  • 541-faster-retransmission-eta
  • 545-avoid-join
  • 545-cache-prepared-statements
  • 545-denormalise-all-the-things
  • 545-denormalise-message-metadata
  • 545-hyper-sql
  • 545-hyper-sql-by-default
  • 545-log-db-row-counts
  • 545-remove-indexes
  • 545-remove-order-by-clause
  • 545-remove-unnecessary-indexes
  • 545-separate-bodies-table
  • 545-shutdown-compact
  • 725-result-handler-rotation-fix
  • 749-android-executor-now-if-possible
  • 752-780-activity-leaks-and-event-handlers
  • 790-ask-before-turning-on-bluetooth
  • 831_refactor_bluetooth_plugins
  • 851-recyclerview-refresher
  • 9-cp-sup
  • 953-check-for-null-message-id
  • 992-refresh-wake-lock
  • 9_copy_paste_support
  • add_special_purpose_contacts
  • add_special_purpose_contacts_refactored
  • asp-temp
  • bdf-string-utils
  • beta-2016-05-13
  • beta-2017-02-21
  • beta-2017-04-07
  • change-password-activity
  • ed25519-migration
  • elliptic-curve-performance-tests
  • factor_out_keyagreement_ui-theme
  • factor_out_plugin_conf
  • fileStorage
  • fix-intro-fragment
  • fix-javadoc
  • fix_bt_test_data
  • fix_nonlocalized_timestamp
  • fix_npe_keyfrag
  • fix_performance_test_db
  • fix_translation_verification
  • gradle-library-versions
  • implement-SyncSession-writer-error-handling
  • implement-chunking
  • implement-mailbox-contact-sessions
  • implement_mailbox_connection_manager
  • language_improvements
  • mailbox
  • mailbox-b
  • mailbox-jd
  • maintenance-0.16
  • master
  • no_screenfilter_warning_splash
  • oreo_bluetooth_address
  • replace_gradle_witness
  • scrypt
  • silence_strict_mode
  • special_purpose_contacts
  • test_data_config
  • testlanguage
  • tor-plugin-detect-connectivity-loss
  • update_external_deps
  • upgrade_roboletric_to_401
  • beta-0.16.1
  • beta-0.16.10
  • beta-0.16.11
  • beta-0.16.12
  • beta-0.16.13
  • beta-0.16.14
  • beta-0.16.15
  • beta-0.16.16
  • beta-0.16.2
  • beta-0.16.3
  • beta-0.16.4
  • beta-0.16.5
  • beta-0.16.6
  • beta-0.16.7
  • beta-0.16.8
  • beta-0.16.9
100 results

Target

Select target project
  • briar/briar
  • goapunk/briar
  • johndoe4221/briar
  • thomas/briar
4 results
Select Git revision
  • 10k-forum-posts
  • 115-tor-performance-measurements
  • 1233-remote-contacts-prototype
  • 1233-remote-contacts-prototype-combined
  • 1233-remote-contacts-prototype-combined-2
  • 1233-remote-contacts-prototype-combined-no-qr
  • 1240-add-methods-for-small-messages
  • 1242-display-image-attachments-fake-data
  • 1242-display-image-attachments-transitions
  • 1251-message-bubble-border
  • 1341-account-manager
  • 1387-persistent-logging
  • 1387-persistent-logging-redux
  • 1473-display-multiple-images-fake-data
  • 1479-show-more-providers
  • 1483-only-group-creator-can-add-members
  • 1528-log-table-names
  • 1592-image-placeholders-concurrent-cache
  • 1592-image-placeholders-debug
  • 1696-migrate-away-from-hardware-backed-key
  • 1712-bluetooth-poll-in-series
  • 1712-detect-bluetooth-connection-limit
  • 1712-motorola-connection-limit
  • 1712-passive-connection-limiter
  • 1712-write-queued-records-before-ending-session
  • 1743-xiaomi-battery-saver
  • 1764-fix-change-app-language-does-not-work-1.2.9
  • 1821-bluetooth-setup-screen
  • 1837-conversation-settings-screen
  • 1866-blog-controller-alt
  • 1881-thread-list-controller-helper-method
  • 1905-use-contact-list-view-model-in-contact-chooser-fragment
  • 1924-fix-sign-out-after-changing-language
  • 2048-allow-webp
  • 2048-webp-image-compression
  • 2057-image-received-crash
  • 2085-transport-keys-for-reintroduced-contact
  • 2165-windows
  • 2211-make-strict-mode-warnings-configurable
  • 2224-fix-building-on-jdk-17
  • 2248-feature-flag-for-introction-client
  • 2343-mailbox-from-maven-local
  • 2343-mailbox-integration-tests
  • 278-bqp-ui-part-2
  • 299-bluetooth-remains-active-after-adding-contact
  • 377_replace_data_structures_with_classes
  • 384-conversation-manager
  • 41-alias-frontend-dialogs
  • 545-log-db-row-counts
  • 68-test-outgoing-message-deletion
  • 725-result-handler-rotation-fix
  • 752-780-activity-leaks-and-event-handlers
  • 831_refactor_bluetooth_plugins
  • 851-recyclerview-refresher
  • 953-check-for-null-message-id
  • Alarms
  • attachment-refactoring
  • avoid-deprecated-network-info-api
  • beta-2016-05-13
  • beta-2017-02-21
  • beta-2017-04-07
  • block-input-stream
  • bluecove-fixes
  • bluetooth-connection-limit
  • bluetooth-polling
  • bluetooth_polling_speedtest
  • briar-as-subproject
  • briar-swing
  • checkstyle
  • checkstyle-plugin
  • ci-debug
  • ci-debugging-hello-world
  • client-versioning-logging
  • contact-refactoring
  • control-port-crash
  • debugging-delay-sending-of-attachments
  • deliver-test-data
  • detect-glibc
  • dont-kill-me-lib
  • earthlingIB-master-patch-81295
  • elliptic-curve-performance-tests
  • export-account-to-sd-card
  • feature-flags-partial-setup
  • fix-database-for-nightly-desktop-users-that-broke-their-db-for-some-contacts
  • fix-screenshot-tests
  • fix_nonlocalized_timestamp
  • gradle-library-versions
  • hash-trees
  • integration-tests-without-implicit-acks
  • introduction-accept-notice-context-sensitive
  • library-desugaring-upgrade-h2
  • limit-in-memory-validation-queue
  • load-forum-post-text-lazily
  • lock-down-navdraweractivity
  • macos
  • maintenance-0.16
  • master
  • misc-code-cleanups
  • nav-drawer-tor-icon
  • network-logging
  • alpha-1.2.0
  • alpha-1.2.1
  • alpha-1.2.15
  • alpha-1.2.16
  • alpha-1.2.17
  • alpha-1.2.18
  • alpha-1.2.19
  • alpha-1.2.2
  • alpha-1.2.20
  • alpha-1.3.0
  • alpha-1.3.1
  • alpha-1.3.2
  • alpha-1.3.3
  • alpha-1.3.4
  • alpha-1.3.5
  • alpha-1.3.6
  • alpha-1.3.8
  • alpha-1.4.0
  • alpha-1.4.1
  • alpha-1.4.10
  • alpha-1.4.11
  • alpha-1.4.12
  • alpha-1.4.13
  • alpha-1.4.14
  • alpha-1.4.15
  • alpha-1.4.17
  • alpha-1.4.18
  • alpha-1.4.19
  • alpha-1.4.20
  • alpha-1.4.21
  • alpha-1.4.22
  • alpha-1.4.23
  • alpha-1.4.3
  • alpha-1.4.4
  • alpha-1.4.5
  • alpha-1.4.6
  • alpha-1.4.7
  • alpha-1.4.8
  • alpha-1.4.9
  • alpha-1.5.0
  • alpha-1.5.1
  • alpha-1.5.10
  • alpha-1.5.11
  • alpha-1.5.12
  • alpha-1.5.13
  • alpha-1.5.14
  • alpha-1.5.2
  • alpha-1.5.3
  • alpha-1.5.4
  • alpha-1.5.5
  • alpha-1.5.6
  • alpha-1.5.7
  • alpha-1.5.8
  • alpha-1.5.9
  • beta-0.16.1
  • beta-0.16.10
  • beta-0.16.11
  • beta-0.16.12
  • beta-0.16.13
  • beta-0.16.14
  • beta-0.16.15
  • beta-0.16.16
  • beta-0.16.17
  • beta-0.16.18
  • beta-0.16.19
  • beta-0.16.2
  • beta-0.16.20
  • beta-0.16.21
  • beta-0.16.3
  • beta-0.16.4
  • beta-0.16.5
  • beta-0.16.6
  • beta-0.16.7
  • beta-0.16.8
  • beta-0.16.9
  • beta-1.1.6
  • beta-1.1.7
  • beta-1.1.8
  • beta-1.1.9
  • beta-1.2.10
  • beta-1.2.11
  • beta-1.2.12
  • beta-1.2.13
  • beta-1.2.14
  • beta-1.2.16
  • beta-1.2.18
  • beta-1.2.20
  • beta-1.2.3
  • beta-1.2.4
  • beta-1.2.5
  • beta-1.2.7
  • beta-1.2.8
  • beta-1.2.9
  • beta-1.3.4
  • beta-1.3.5
  • beta-1.3.6
  • beta-1.3.8
  • beta-1.4.1
  • beta-1.4.10
  • beta-1.4.11
200 results
Show changes
Commits on Source (4)
Showing
with 149 additions and 173 deletions
......@@ -57,10 +57,9 @@
<string name="contact_exchange_failed">Contact exchange failed</string>
<string name="scan_qr_code">Scan QR code</string>
<string name="qr_code_invalid">The QR code is invalid</string>
<string name="could_not_open_camera">Could not open camera</string>
<string name="connecting_to_device">Connecting to device\u2026</string>
<string name="authenticating_with_device">Authenticating with device\u2026</string>
<string name="connection_aborted_local">Connection aborted by us! This could mean that someone is trying to interfere with your connection</string>
<string name="connection_aborted_remote">Connection aborted by your contact! This could mean that someone is trying to interfere with your connection</string>
<string name="no_private_messages">No messages</string>
<string name="private_message_hint">Type message</string>
<string name="message_sent_toast">Message sent</string>
......
......@@ -5,10 +5,12 @@ import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.Bitmap;
import android.hardware.Camera;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.FragmentActivity;
import android.util.Base64;
import android.view.Display;
import android.view.LayoutInflater;
......@@ -21,6 +23,7 @@ import android.widget.TextView;
import android.widget.Toast;
import com.google.zxing.Result;
import com.google.zxing.WriterException;
import org.briarproject.R;
import org.briarproject.android.AndroidComponent;
......@@ -50,6 +53,7 @@ import static android.bluetooth.BluetoothAdapter.ACTION_STATE_CHANGED;
import static android.bluetooth.BluetoothAdapter.EXTRA_STATE;
import static android.bluetooth.BluetoothAdapter.STATE_ON;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_NOSENSOR;
import static android.view.View.GONE;
import static android.widget.LinearLayout.HORIZONTAL;
import static android.widget.LinearLayout.VERTICAL;
import static android.widget.Toast.LENGTH_LONG;
......@@ -59,6 +63,8 @@ import static java.util.logging.Level.WARNING;
public class ShowQrCodeFragment extends BaseEventFragment
implements QrCodeDecoder.ResultCallback {
private static final int CAMERA_MAX_RETRIES = 3;
private static final int CAMERA_RETRY_DELAY = 500; // Milliseconds
private static final Logger LOG =
Logger.getLogger(ShowQrCodeFragment.class.getName());
......@@ -194,71 +200,68 @@ public class ShowQrCodeFragment extends BaseEventFragment
private void openCamera() {
AsyncTask<Void, Void, Camera> openTask =
new AsyncTask<Void, Void, Camera>() {
@Override
protected Camera doInBackground(Void... unused) {
LOG.info("Opening camera");
// Work around transient failures
for (int i = 0; i < CAMERA_MAX_RETRIES; i++) {
try {
return Camera.open();
} catch (RuntimeException e) {
LOG.log(WARNING,
"Error opening camera, trying again", e);
try {
Thread.sleep(1000);
} catch (InterruptedException e2) {
LOG.info("Interrupted before second attempt");
return null;
LOG.warning("Error opening camera: " + e);
}
try {
return Camera.open();
} catch (RuntimeException e2) {
LOG.log(WARNING, "Error opening camera", e2);
Thread.sleep(CAMERA_RETRY_DELAY);
} catch (InterruptedException e) {
LOG.info("Interrupted while opening camera");
return null;
}
}
LOG.info("Failed to open camera");
return null;
}
@Override
protected void onPostExecute(Camera camera) {
if (camera == null) {
// TODO better solution?
getActivity().finish();
} else {
cameraView.start(camera, decoder, 0);
}
if (camera == null)
showToastAndFinish(R.string.could_not_open_camera);
else cameraView.start(camera, decoder, 0);
}
};
openTask.execute();
}
private void showToastAndFinish(int resid) {
FragmentActivity fa = getActivity();
if (fa != null) {
Toast.makeText(fa, resid, LENGTH_LONG).show();
fa.finish();
}
}
private void releaseCamera() {
LOG.info("Releasing camera");
try {
cameraView.stop();
} catch (RuntimeException e) {
LOG.log(WARNING, "Error releasing camera", e);
// TODO better solution
getActivity().finish();
}
}
private void reset() {
cameraView.setVisibility(View.VISIBLE);
startListening();
openCamera();
}
private void qrCodeScanned(String content) {
try {
// TODO use Base32
Payload remotePayload = payloadParser.parse(
Base64.decode(content, 0));
cameraView.setVisibility(View.GONE);
byte[] payloadBytes = Base64.decode(content, 0);
Payload remotePayload = payloadParser.parse(payloadBytes);
cameraView.setVisibility(GONE);
status.setText(R.string.connecting_to_device);
task.connectAndRunProtocol(remotePayload);
} catch (IllegalArgumentException e) {
// Thrown by Base64.decode() if incorrectly padded
showToastAndFinish(R.string.qr_code_invalid);
} catch (IOException e) {
// TODO show failure
Toast.makeText(getActivity(), R.string.qr_code_invalid,
LENGTH_LONG).show();
showToastAndFinish(R.string.qr_code_invalid);
}
}
......@@ -274,8 +277,7 @@ public class ShowQrCodeFragment extends BaseEventFragment
} else if (e instanceof KeyAgreementStartedEvent) {
keyAgreementStarted();
} else if (e instanceof KeyAgreementAbortedEvent) {
KeyAgreementAbortedEvent event = (KeyAgreementAbortedEvent) e;
keyAgreementAborted(event.didRemoteAbort());
keyAgreementFailed();
}
}
......@@ -284,14 +286,22 @@ public class ShowQrCodeFragment extends BaseEventFragment
@Override
public void run() {
// TODO use Base32
String input = Base64.encodeToString(
payloadEncoder.encode(localPayload), 0);
qrCode.setImageBitmap(
QrCodeUtils.createQrCode(getActivity(), input));
byte[] payloadBytes = payloadEncoder.encode(localPayload);
String base64 = Base64.encodeToString(payloadBytes, 0);
// The fragment may no longer belong to an activity
FragmentActivity fa = getActivity();
if (fa == null) return;
try {
Bitmap bitmap = QrCodeUtils.createQrCode(fa, base64);
qrCode.setImageBitmap(bitmap);
// Simple fade-in animation
AlphaAnimation anim = new AlphaAnimation(0.0f, 1.0f);
anim.setDuration(200);
qrCode.startAnimation(anim);
} catch (WriterException e) {
if (LOG.isLoggable(WARNING))
LOG.log(WARNING, e.toString(), e);
}
}
});
}
......@@ -300,10 +310,7 @@ public class ShowQrCodeFragment extends BaseEventFragment
listener.runOnUiThread(new Runnable() {
@Override
public void run() {
reset();
// TODO show failure somewhere persistent?
Toast.makeText(getActivity(), R.string.connection_failed,
LENGTH_LONG).show();
showToastAndFinish(R.string.connection_failed);
}
});
}
......@@ -327,21 +334,6 @@ public class ShowQrCodeFragment extends BaseEventFragment
});
}
private void keyAgreementAborted(final boolean remoteAborted) {
listener.runOnUiThread(new Runnable() {
@Override
public void run() {
reset();
listener.hideLoadingScreen();
// TODO show abort somewhere persistent?
Toast.makeText(getActivity(),
remoteAborted ? R.string.connection_aborted_remote :
R.string.connection_aborted_local, LENGTH_LONG)
.show();
}
});
}
@Override
public void handleResult(final Result result) {
listener.runOnUiThread(new Runnable() {
......
......@@ -2,50 +2,39 @@ package org.briarproject.android.util;
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.util.DisplayMetrics;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.WriterException;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.QRCodeWriter;
import java.util.logging.Logger;
import static java.util.logging.Level.WARNING;
import static android.graphics.Bitmap.Config.ARGB_8888;
import static android.graphics.Color.BLACK;
import static android.graphics.Color.WHITE;
import static com.google.zxing.BarcodeFormat.QR_CODE;
public class QrCodeUtils {
private static final Logger LOG =
Logger.getLogger(QrCodeUtils.class.getName());
public static Bitmap createQrCode(Activity activity, String input) {
public static Bitmap createQrCode(Activity activity, String input)
throws WriterException {
// Get narrowest screen dimension
DisplayMetrics dm = new DisplayMetrics();
activity.getWindowManager().getDefaultDisplay().getMetrics(dm);
int smallestDimen = Math.min(dm.widthPixels, dm.heightPixels);
try {
// Generate QR code
final BitMatrix encoded = new QRCodeWriter().encode(
input, BarcodeFormat.QR_CODE, smallestDimen, smallestDimen);
BitMatrix encoded = new QRCodeWriter().encode(input, QR_CODE,
smallestDimen, smallestDimen);
// Convert QR code to Bitmap
int width = encoded.getWidth();
int height = encoded.getHeight();
int[] pixels = new int[width * height];
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
pixels[y * width + x] =
encoded.get(x, y) ? Color.BLACK : Color.WHITE;
pixels[y * width + x] = encoded.get(x, y) ? BLACK : WHITE;
}
}
Bitmap qr = Bitmap.createBitmap(width, height,
Bitmap.Config.ARGB_8888);
Bitmap qr = Bitmap.createBitmap(width, height, ARGB_8888);
qr.setPixels(pixels, 0, width, 0, 0, width, height);
return qr;
} catch (WriterException e) {
if (LOG.isLoggable(WARNING))
LOG.log(WARNING, e.toString(), e);
return null;
}
}
}
......@@ -9,9 +9,9 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import org.briarproject.android.api.AndroidExecutor;
import org.briarproject.android.util.AndroidUtils;
import org.briarproject.api.TransportId;
import org.briarproject.android.api.AndroidExecutor;
import org.briarproject.api.contact.ContactId;
import org.briarproject.api.crypto.PseudoRandom;
import org.briarproject.api.keyagreement.KeyAgreementConnection;
......@@ -451,7 +451,7 @@ class DroidtoothPlugin implements DuplexPlugin {
public DuplexTransportConnection createKeyAgreementConnection(
byte[] remoteCommitment, TransportDescriptor d, long timeout) {
if (!isRunning()) return null;
if (!ID.equals(d.getIdentifier())) return null;
if (!ID.equals(d.getId())) return null;
TransportProperties p = d.getProperties();
if (p == null) return null;
String address = p.get(PROP_ADDRESS);
......@@ -610,8 +610,7 @@ class DroidtoothPlugin implements DuplexPlugin {
@Override
public KeyAgreementConnection call() throws IOException {
BluetoothSocket s = ss.accept();
if (LOG.isLoggable(INFO))
LOG.info(ID.getString() + ": Incoming connection");
LOG.info("Incoming connection");
return new KeyAgreementConnection(
new DroidtoothTransportConnection(
DroidtoothPlugin.this, s), ID);
......@@ -621,6 +620,7 @@ class DroidtoothPlugin implements DuplexPlugin {
@Override
public void close() {
LOG.info("Closing listening socket");
try {
ss.close();
} catch (IOException e) {
......
......@@ -17,7 +17,7 @@ public class TransportDescriptor {
}
/** Returns the transport identifier. */
public TransportId getIdentifier() {
public TransportId getId() {
return id;
}
......
......@@ -6,6 +6,7 @@ import org.briarproject.api.keyagreement.KeyAgreementConnection;
import org.briarproject.api.keyagreement.KeyAgreementListener;
import org.briarproject.api.keyagreement.Payload;
import org.briarproject.api.keyagreement.TransportDescriptor;
import org.briarproject.api.plugins.Plugin;
import org.briarproject.api.plugins.PluginManager;
import org.briarproject.api.plugins.duplex.DuplexPlugin;
import org.briarproject.api.plugins.duplex.DuplexTransportConnection;
......@@ -17,6 +18,7 @@ import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletionService;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorCompletionService;
......@@ -47,8 +49,8 @@ class KeyAgreementConnector {
new ArrayList<KeyAgreementListener>();
private final List<Future<KeyAgreementConnection>> pending =
new ArrayList<Future<KeyAgreementConnection>>();
private final CountDownLatch aliceLatch = new CountDownLatch(1);
private volatile boolean connecting = false;
private volatile boolean alice = false;
public KeyAgreementConnector(Callbacks callbacks, Clock clock,
......@@ -65,8 +67,8 @@ class KeyAgreementConnector {
public Payload listen(KeyPair localKeyPair) {
LOG.info("Starting BQP listeners");
// Derive commitment
byte[] commitment = crypto.deriveKeyCommitment(
localKeyPair.getPublic().getEncoded());
byte[] publicKey = localKeyPair.getPublic().getEncoded();
byte[] commitment = crypto.deriveKeyCommitment(publicKey);
// Start all listeners and collect their descriptors
List<TransportDescriptor> descriptors =
new ArrayList<TransportDescriptor>();
......@@ -85,39 +87,39 @@ class KeyAgreementConnector {
public void stopListening() {
LOG.info("Stopping BQP listeners");
for (KeyAgreementListener l : listeners) {
l.close();
}
listeners.clear();
for (KeyAgreementListener l : listeners) l.close();
}
public KeyAgreementTransport connect(Payload remotePayload,
boolean alice) {
// Let the listeners know if we are Alice
this.connecting = true;
public KeyAgreementTransport connect(Payload remotePayload, boolean alice) {
// Let the readable tasks know if we are Alice
this.alice = alice;
aliceLatch.countDown();
long end = clock.currentTimeMillis() + CONNECTION_TIMEOUT;
// Start connecting over supported transports
LOG.info("Starting outgoing BQP connections");
for (TransportDescriptor d : remotePayload.getTransportDescriptors()) {
DuplexPlugin plugin = (DuplexPlugin) pluginManager.getPlugin(
d.getIdentifier());
if (plugin != null)
pending.add(connect.submit(new ReadableTask(
new ConnectorTask(plugin, remotePayload.getCommitment(),
d, end))));
Plugin p = pluginManager.getPlugin(d.getId());
if (p != null && p instanceof DuplexPlugin) {
DuplexPlugin plugin = (DuplexPlugin) p;
pending.add(connect.submit(new ReadableTask(new ConnectorTask(
plugin, remotePayload.getCommitment(), d, end))));
}
}
// Get chosen connection
KeyAgreementConnection chosen = null;
try {
LOG.info("Waiting for connection");
long now = clock.currentTimeMillis();
Future<KeyAgreementConnection> f =
connect.poll(end - now, MILLISECONDS);
if (f == null)
return null; // No task completed within the timeout.
if (f == null) {
LOG.info("No connection within timeout");
return null;
}
chosen = f.get();
if (chosen == null) throw new IllegalStateException();
return new KeyAgreementTransport(chosen);
} catch (InterruptedException e) {
LOG.info("Interrupted while waiting for connection");
......@@ -138,16 +140,18 @@ class KeyAgreementConnector {
private void closePending(KeyAgreementConnection chosen) {
for (Future<KeyAgreementConnection> f : pending) {
if (f.cancel(true)) {
LOG.info("Cancelled redundant task");
} else {
try {
if (f.cancel(true))
LOG.info("Cancelled task");
else if (!f.isCancelled()) {
KeyAgreementConnection c = f.get();
if (c != null && c != chosen)
tryToClose(c.getConnection(), false);
if (c == null) throw new IllegalStateException();
if (c != chosen) {
LOG.info("Closing redundant connection");
tryToClose(c.getConnection());
}
} catch (InterruptedException e) {
LOG.info("Interrupted while closing sockets");
LOG.info("Interrupted while closing connections");
Thread.currentThread().interrupt();
return;
} catch (ExecutionException e) {
......@@ -155,13 +159,12 @@ class KeyAgreementConnector {
}
}
}
}
private void tryToClose(DuplexTransportConnection conn, boolean exception) {
private void tryToClose(DuplexTransportConnection conn) {
try {
if (LOG.isLoggable(INFO))
LOG.info("Closing connection, exception: " + exception);
conn.getReader().dispose(exception, true);
conn.getWriter().dispose(exception);
conn.getReader().dispose(false, true);
conn.getWriter().dispose(false);
} catch (IOException e) {
if (LOG.isLoggable(INFO)) LOG.info(e.toString());
}
......@@ -185,25 +188,24 @@ class KeyAgreementConnector {
@Override
public KeyAgreementConnection call() throws Exception {
// Repeat attempts until we connect or get interrupted
while (true) {
long now = clock.currentTimeMillis();
while (now < end) {
DuplexTransportConnection conn =
plugin.createKeyAgreementConnection(commitment,
descriptor, end - now);
if (conn != null) {
if (LOG.isLoggable(INFO))
LOG.info(plugin.getId().getString() +
": Outgoing connection");
LOG.info("Outgoing connection");
return new KeyAgreementConnection(conn, plugin.getId());
}
// Wait 2s before retry (to circumvent transient failures)
Thread.sleep(2000);
now = clock.currentTimeMillis();
}
throw new IOException("Timed out");
}
}
private class ReadableTask
implements Callable<KeyAgreementConnection> {
private class ReadableTask implements Callable<KeyAgreementConnection> {
private final Callable<KeyAgreementConnection> connectionTask;
......@@ -212,24 +214,22 @@ class KeyAgreementConnector {
}
@Override
public KeyAgreementConnection call()
throws Exception {
public KeyAgreementConnection call() throws Exception {
KeyAgreementConnection c = connectionTask.call();
InputStream in = c.getConnection().getReader().getInputStream();
aliceLatch.await();
if (alice) return c;
boolean waitingSent = false;
while (!alice && in.available() == 0) {
if (!waitingSent && connecting && !alice) {
while (in.available() == 0) {
if (!waitingSent) {
// Bob waits here until Alice obtains his payload.
callbacks.connectionWaiting();
waitingSent = true;
}
if (LOG.isLoggable(INFO))
LOG.info(c.getTransportId().toString() +
": Waiting for connection");
LOG.info("Waiting for data");
Thread.sleep(1000);
}
if (!alice && LOG.isLoggable(INFO))
LOG.info(c.getTransportId().toString() + ": Data available");
LOG.info("Data available");
return c;
}
}
......
......@@ -36,8 +36,8 @@ class KeyAgreementTaskImpl extends Thread implements
private final KeyPair localKeyPair;
private final KeyAgreementConnector connector;
private Payload localPayload;
private Payload remotePayload;
private volatile Payload localPayload;
private volatile Payload remotePayload;
public KeyAgreementTaskImpl(Clock clock, CryptoComponent crypto,
EventBus eventBus, PayloadEncoder payloadEncoder,
......@@ -61,21 +61,17 @@ class KeyAgreementTaskImpl extends Thread implements
@Override
public synchronized void stopListening() {
if (localPayload != null) {
if (remotePayload == null)
connector.stopListening();
else
interrupt();
if (remotePayload == null) connector.stopListening();
else interrupt();
}
}
@Override
public synchronized void connectAndRunProtocol(Payload remotePayload) {
if (this.localPayload == null)
throw new IllegalStateException(
"Must listen before connecting");
throw new IllegalStateException("Must listen before connecting");
if (this.remotePayload != null)
throw new IllegalStateException(
"Already provided remote payload for this task");
throw new IllegalStateException("Already provided remote payload");
this.remotePayload = remotePayload;
start();
}
......
......@@ -33,7 +33,7 @@ class PayloadEncoderImpl implements PayloadEncoder {
w.writeListStart(); // Descriptors start
for (TransportDescriptor d : p.getTransportDescriptors()) {
w.writeListStart();
w.writeString(d.getIdentifier().getString());
w.writeString(d.getId().getString());
w.writeDictionary(d.getProperties());
w.writeListEnd();
}
......
......@@ -35,18 +35,18 @@ class PayloadParserImpl implements PayloadParser {
BdfReader r = bdfReaderFactory.createReader(in);
r.readListStart(); // Payload start
int proto = (int) r.readLong();
if (proto != PROTOCOL_VERSION)
throw new FormatException();
if (proto != PROTOCOL_VERSION) throw new FormatException();
byte[] commitment = r.readRaw(COMMIT_LENGTH);
if (commitment.length != COMMIT_LENGTH)
throw new FormatException();
List<TransportDescriptor> descriptors = new ArrayList<TransportDescriptor>();
if (commitment.length != COMMIT_LENGTH) throw new FormatException();
List<TransportDescriptor> descriptors =
new ArrayList<TransportDescriptor>();
r.readListStart(); // Descriptors start
while (r.hasList()) {
while (!r.hasListEnd()) {
r.readListStart();
while (!r.hasListEnd()) {
TransportId id =
new TransportId(r.readString(MAX_PROPERTY_LENGTH));
String idString = r.readString(MAX_PROPERTY_LENGTH);
if (idString.isEmpty()) throw new FormatException();
TransportId id = new TransportId(idString);
TransportProperties p = new TransportProperties();
r.readDictionaryStart();
while (!r.hasDictionaryEnd()) {
......@@ -61,8 +61,7 @@ class PayloadParserImpl implements PayloadParser {
}
r.readListEnd(); // Descriptors end
r.readListEnd(); // Payload end
if (!r.eof())
throw new FormatException();
if (!r.eof()) throw new FormatException();
return new Payload(commitment, descriptors);
}
}
......@@ -374,7 +374,7 @@ class BluetoothPlugin implements DuplexPlugin {
public DuplexTransportConnection createKeyAgreementConnection(
byte[] remoteCommitment, TransportDescriptor d, long timeout) {
if (!isRunning()) return null;
if (!ID.equals(d.getIdentifier())) return null;
if (!ID.equals(d.getId())) return null;
TransportProperties p = d.getProperties();
if (p == null) return null;
String address = p.get(PROP_ADDRESS);
......@@ -486,7 +486,7 @@ class BluetoothPlugin implements DuplexPlugin {
public KeyAgreementConnection call() throws Exception {
StreamConnection s = ss.acceptAndOpen();
if (LOG.isLoggable(INFO))
LOG.info(ID.getString() + ": Incoming connection");
LOG.info(ID + ": Incoming connection");
return new KeyAgreementConnection(
new BluetoothTransportConnection(
BluetoothPlugin.this, s), ID);
......@@ -496,6 +496,7 @@ class BluetoothPlugin implements DuplexPlugin {
@Override
public void close() {
LOG.info("Closing key agreement listening socket");
try {
ss.close();
} catch (IOException e) {
......