mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-16 20:59:54 +01:00
Merge branch 'start-plugins-async' into 'master'
Start plugins asynchronously This prevents other services from getting stuck behind the plugin manager while the Tor plugin is starting, which takes several seconds. The plugin manager waits for each plugin to start before stopping it. I've also added some canaries to plugins and services to ensure instances aren't started more than once. See merge request !181
This commit is contained in:
@@ -42,6 +42,7 @@ import java.util.concurrent.Callable;
|
|||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
import java.util.concurrent.Future;
|
import java.util.concurrent.Future;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
@@ -81,10 +82,10 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
|
|||||||
private final Context appContext;
|
private final Context appContext;
|
||||||
|
|
||||||
// The following must only be accessed on the main UI thread
|
// The following must only be accessed on the main UI thread
|
||||||
private final Map<GroupId, Integer> contactCounts =
|
private final Map<GroupId, Integer> contactCounts = new HashMap<>();
|
||||||
new HashMap<GroupId, Integer>();
|
private final Map<GroupId, Integer> forumCounts = new HashMap<>();
|
||||||
private final Map<GroupId, Integer> forumCounts =
|
private final AtomicBoolean used = new AtomicBoolean(false);
|
||||||
new HashMap<GroupId, Integer>();
|
|
||||||
private int contactTotal = 0, forumTotal = 0;
|
private int contactTotal = 0, forumTotal = 0;
|
||||||
private int nextRequestId = 0;
|
private int nextRequestId = 0;
|
||||||
private GroupId visibleGroup = null;
|
private GroupId visibleGroup = null;
|
||||||
@@ -106,6 +107,7 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void startService() throws ServiceException {
|
public void startService() throws ServiceException {
|
||||||
|
if (used.getAndSet(true)) throw new IllegalStateException();
|
||||||
try {
|
try {
|
||||||
settings = settingsManager.getSettings(SETTINGS_NAMESPACE);
|
settings = settingsManager.getSettings(SETTINGS_NAMESPACE);
|
||||||
} catch (DbException e) {
|
} catch (DbException e) {
|
||||||
@@ -116,6 +118,7 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
|
|||||||
@Override
|
@Override
|
||||||
public void stopService() throws ServiceException {
|
public void stopService() throws ServiceException {
|
||||||
Future<Void> f = androidExecutor.submit(new Callable<Void>() {
|
Future<Void> f = androidExecutor.submit(new Callable<Void>() {
|
||||||
|
@Override
|
||||||
public Void call() {
|
public Void call() {
|
||||||
clearPrivateMessageNotification();
|
clearPrivateMessageNotification();
|
||||||
clearForumPostNotification();
|
clearForumPostNotification();
|
||||||
@@ -125,9 +128,7 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
|
|||||||
});
|
});
|
||||||
try {
|
try {
|
||||||
f.get();
|
f.get();
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException | ExecutionException e) {
|
||||||
throw new ServiceException(e);
|
|
||||||
} catch (ExecutionException e) {
|
|
||||||
throw new ServiceException(e);
|
throw new ServiceException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -150,6 +151,7 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
|
|||||||
nm.cancel(INTRODUCTION_SUCCESS_NOTIFICATION_ID);
|
nm.cancel(INTRODUCTION_SUCCESS_NOTIFICATION_ID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void eventOccurred(Event e) {
|
public void eventOccurred(Event e) {
|
||||||
if (e instanceof SettingsUpdatedEvent) {
|
if (e instanceof SettingsUpdatedEvent) {
|
||||||
SettingsUpdatedEvent s = (SettingsUpdatedEvent) e;
|
SettingsUpdatedEvent s = (SettingsUpdatedEvent) e;
|
||||||
@@ -180,6 +182,7 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
|
|||||||
|
|
||||||
private void loadSettings() {
|
private void loadSettings() {
|
||||||
dbExecutor.execute(new Runnable() {
|
dbExecutor.execute(new Runnable() {
|
||||||
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
settings = settingsManager.getSettings(SETTINGS_NAMESPACE);
|
settings = settingsManager.getSettings(SETTINGS_NAMESPACE);
|
||||||
@@ -191,8 +194,10 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void showPrivateMessageNotification(final GroupId g) {
|
public void showPrivateMessageNotification(final GroupId g) {
|
||||||
androidExecutor.execute(new Runnable() {
|
androidExecutor.execute(new Runnable() {
|
||||||
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
Integer count = contactCounts.get(g);
|
Integer count = contactCounts.get(g);
|
||||||
if (count == null) contactCounts.put(g, 1);
|
if (count == null) contactCounts.put(g, 1);
|
||||||
@@ -204,8 +209,10 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void clearPrivateMessageNotification(final GroupId g) {
|
public void clearPrivateMessageNotification(final GroupId g) {
|
||||||
androidExecutor.execute(new Runnable() {
|
androidExecutor.execute(new Runnable() {
|
||||||
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
Integer count = contactCounts.remove(g);
|
Integer count = contactCounts.remove(g);
|
||||||
if (count == null) return; // Already cleared
|
if (count == null) return; // Already cleared
|
||||||
@@ -275,8 +282,10 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
|
|||||||
return defaults;
|
return defaults;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void showForumPostNotification(final GroupId g) {
|
public void showForumPostNotification(final GroupId g) {
|
||||||
androidExecutor.execute(new Runnable() {
|
androidExecutor.execute(new Runnable() {
|
||||||
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
Integer count = forumCounts.get(g);
|
Integer count = forumCounts.get(g);
|
||||||
if (count == null) forumCounts.put(g, 1);
|
if (count == null) forumCounts.put(g, 1);
|
||||||
@@ -288,8 +297,10 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void clearForumPostNotification(final GroupId g) {
|
public void clearForumPostNotification(final GroupId g) {
|
||||||
androidExecutor.execute(new Runnable() {
|
androidExecutor.execute(new Runnable() {
|
||||||
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
Integer count = forumCounts.remove(g);
|
Integer count = forumCounts.remove(g);
|
||||||
if (count == null) return; // Already cleared
|
if (count == null) return; // Already cleared
|
||||||
@@ -347,16 +358,20 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void blockNotification(final GroupId g) {
|
public void blockNotification(final GroupId g) {
|
||||||
androidExecutor.execute(new Runnable() {
|
androidExecutor.execute(new Runnable() {
|
||||||
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
visibleGroup = g;
|
visibleGroup = g;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void unblockNotification(final GroupId g) {
|
public void unblockNotification(final GroupId g) {
|
||||||
androidExecutor.execute(new Runnable() {
|
androidExecutor.execute(new Runnable() {
|
||||||
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
if (g.equals(visibleGroup)) visibleGroup = null;
|
if (g.equals(visibleGroup)) visibleGroup = null;
|
||||||
}
|
}
|
||||||
@@ -365,6 +380,7 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
|
|||||||
|
|
||||||
private void showNotificationForPrivateConversation(final ContactId c) {
|
private void showNotificationForPrivateConversation(final ContactId c) {
|
||||||
androidExecutor.execute(new Runnable() {
|
androidExecutor.execute(new Runnable() {
|
||||||
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
GroupId group = messagingManager.getConversationId(c);
|
GroupId group = messagingManager.getConversationId(c);
|
||||||
@@ -379,6 +395,7 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
|
|||||||
|
|
||||||
private void showIntroductionSucceededNotification(final Contact c) {
|
private void showIntroductionSucceededNotification(final Contact c) {
|
||||||
androidExecutor.execute(new Runnable() {
|
androidExecutor.execute(new Runnable() {
|
||||||
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
NotificationCompat.Builder b =
|
NotificationCompat.Builder b =
|
||||||
new NotificationCompat.Builder(appContext);
|
new NotificationCompat.Builder(appContext);
|
||||||
|
|||||||
@@ -9,9 +9,9 @@ import android.content.Context;
|
|||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.IntentFilter;
|
import android.content.IntentFilter;
|
||||||
|
|
||||||
|
import org.briarproject.android.api.AndroidExecutor;
|
||||||
import org.briarproject.android.util.AndroidUtils;
|
import org.briarproject.android.util.AndroidUtils;
|
||||||
import org.briarproject.api.TransportId;
|
import org.briarproject.api.TransportId;
|
||||||
import org.briarproject.android.api.AndroidExecutor;
|
|
||||||
import org.briarproject.api.contact.ContactId;
|
import org.briarproject.api.contact.ContactId;
|
||||||
import org.briarproject.api.crypto.PseudoRandom;
|
import org.briarproject.api.crypto.PseudoRandom;
|
||||||
import org.briarproject.api.keyagreement.KeyAgreementConnection;
|
import org.briarproject.api.keyagreement.KeyAgreementConnection;
|
||||||
@@ -41,6 +41,7 @@ import java.util.concurrent.ExecutionException;
|
|||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
import java.util.concurrent.ExecutorCompletionService;
|
import java.util.concurrent.ExecutorCompletionService;
|
||||||
import java.util.concurrent.Future;
|
import java.util.concurrent.Future;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import static android.bluetooth.BluetoothAdapter.ACTION_SCAN_MODE_CHANGED;
|
import static android.bluetooth.BluetoothAdapter.ACTION_SCAN_MODE_CHANGED;
|
||||||
@@ -80,6 +81,7 @@ class DroidtoothPlugin implements DuplexPlugin {
|
|||||||
private final Backoff backoff;
|
private final Backoff backoff;
|
||||||
private final DuplexPluginCallback callback;
|
private final DuplexPluginCallback callback;
|
||||||
private final int maxLatency;
|
private final int maxLatency;
|
||||||
|
private final AtomicBoolean used = new AtomicBoolean(false);
|
||||||
|
|
||||||
private volatile boolean running = false;
|
private volatile boolean running = false;
|
||||||
private volatile boolean wasEnabledByUs = false;
|
private volatile boolean wasEnabledByUs = false;
|
||||||
@@ -101,24 +103,30 @@ class DroidtoothPlugin implements DuplexPlugin {
|
|||||||
this.maxLatency = maxLatency;
|
this.maxLatency = maxLatency;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public TransportId getId() {
|
public TransportId getId() {
|
||||||
return ID;
|
return ID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public int getMaxLatency() {
|
public int getMaxLatency() {
|
||||||
return maxLatency;
|
return maxLatency;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public int getMaxIdleTime() {
|
public int getMaxIdleTime() {
|
||||||
// Bluetooth detects dead connections so we don't need keepalives
|
// Bluetooth detects dead connections so we don't need keepalives
|
||||||
return Integer.MAX_VALUE;
|
return Integer.MAX_VALUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public boolean start() throws IOException {
|
public boolean start() throws IOException {
|
||||||
|
if (used.getAndSet(true)) throw new IllegalStateException();
|
||||||
// BluetoothAdapter.getDefaultAdapter() must be called on a thread
|
// BluetoothAdapter.getDefaultAdapter() must be called on a thread
|
||||||
// with a message queue, so submit it to the AndroidExecutor
|
// with a message queue, so submit it to the AndroidExecutor
|
||||||
try {
|
try {
|
||||||
adapter = androidExecutor.submit(new Callable<BluetoothAdapter>() {
|
adapter = androidExecutor.submit(new Callable<BluetoothAdapter>() {
|
||||||
|
@Override
|
||||||
public BluetoothAdapter call() throws Exception {
|
public BluetoothAdapter call() throws Exception {
|
||||||
return BluetoothAdapter.getDefaultAdapter();
|
return BluetoothAdapter.getDefaultAdapter();
|
||||||
}
|
}
|
||||||
@@ -158,6 +166,7 @@ class DroidtoothPlugin implements DuplexPlugin {
|
|||||||
|
|
||||||
private void bind() {
|
private void bind() {
|
||||||
ioExecutor.execute(new Runnable() {
|
ioExecutor.execute(new Runnable() {
|
||||||
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
if (!isRunning()) return;
|
if (!isRunning()) return;
|
||||||
String address = AndroidUtils.getBluetoothAddress(appContext,
|
String address = AndroidUtils.getBluetoothAddress(appContext,
|
||||||
@@ -238,6 +247,7 @@ class DroidtoothPlugin implements DuplexPlugin {
|
|||||||
return new DroidtoothTransportConnection(this, s);
|
return new DroidtoothTransportConnection(this, s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void stop() {
|
public void stop() {
|
||||||
running = false;
|
running = false;
|
||||||
if (receiver != null) appContext.unregisterReceiver(receiver);
|
if (receiver != null) appContext.unregisterReceiver(receiver);
|
||||||
@@ -249,18 +259,22 @@ class DroidtoothPlugin implements DuplexPlugin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public boolean isRunning() {
|
public boolean isRunning() {
|
||||||
return running && adapter.isEnabled();
|
return running && adapter.isEnabled();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public boolean shouldPoll() {
|
public boolean shouldPoll() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public int getPollingInterval() {
|
public int getPollingInterval() {
|
||||||
return backoff.getPollingInterval();
|
return backoff.getPollingInterval();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void poll(Collection<ContactId> connected) {
|
public void poll(Collection<ContactId> connected) {
|
||||||
if (!isRunning()) return;
|
if (!isRunning()) return;
|
||||||
backoff.increment();
|
backoff.increment();
|
||||||
@@ -275,6 +289,7 @@ class DroidtoothPlugin implements DuplexPlugin {
|
|||||||
final String uuid = e.getValue().get(PROP_UUID);
|
final String uuid = e.getValue().get(PROP_UUID);
|
||||||
if (StringUtils.isNullOrEmpty(uuid)) continue;
|
if (StringUtils.isNullOrEmpty(uuid)) continue;
|
||||||
ioExecutor.execute(new Runnable() {
|
ioExecutor.execute(new Runnable() {
|
||||||
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
if (!running) return;
|
if (!running) return;
|
||||||
BluetoothSocket s = connect(address, uuid);
|
BluetoothSocket s = connect(address, uuid);
|
||||||
@@ -327,6 +342,7 @@ class DroidtoothPlugin implements DuplexPlugin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public DuplexTransportConnection createConnection(ContactId c) {
|
public DuplexTransportConnection createConnection(ContactId c) {
|
||||||
if (!isRunning()) return null;
|
if (!isRunning()) return null;
|
||||||
TransportProperties p = callback.getRemoteProperties().get(c);
|
TransportProperties p = callback.getRemoteProperties().get(c);
|
||||||
@@ -340,10 +356,12 @@ class DroidtoothPlugin implements DuplexPlugin {
|
|||||||
return new DroidtoothTransportConnection(this, s);
|
return new DroidtoothTransportConnection(this, s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public boolean supportsInvitations() {
|
public boolean supportsInvitations() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public DuplexTransportConnection createInvitationConnection(PseudoRandom r,
|
public DuplexTransportConnection createInvitationConnection(PseudoRandom r,
|
||||||
long timeout, boolean alice) {
|
long timeout, boolean alice) {
|
||||||
if (!isRunning()) return null;
|
if (!isRunning()) return null;
|
||||||
@@ -361,9 +379,8 @@ class DroidtoothPlugin implements DuplexPlugin {
|
|||||||
}
|
}
|
||||||
// Create the background tasks
|
// Create the background tasks
|
||||||
CompletionService<BluetoothSocket> complete =
|
CompletionService<BluetoothSocket> complete =
|
||||||
new ExecutorCompletionService<BluetoothSocket>(ioExecutor);
|
new ExecutorCompletionService<>(ioExecutor);
|
||||||
List<Future<BluetoothSocket>> futures =
|
List<Future<BluetoothSocket>> futures = new ArrayList<>();
|
||||||
new ArrayList<Future<BluetoothSocket>>();
|
|
||||||
if (alice) {
|
if (alice) {
|
||||||
// Return the first connected socket
|
// Return the first connected socket
|
||||||
futures.add(complete.submit(new ListeningTask(ss)));
|
futures.add(complete.submit(new ListeningTask(ss)));
|
||||||
@@ -398,6 +415,7 @@ class DroidtoothPlugin implements DuplexPlugin {
|
|||||||
private void closeSockets(final List<Future<BluetoothSocket>> futures,
|
private void closeSockets(final List<Future<BluetoothSocket>> futures,
|
||||||
final BluetoothSocket chosen) {
|
final BluetoothSocket chosen) {
|
||||||
ioExecutor.execute(new Runnable() {
|
ioExecutor.execute(new Runnable() {
|
||||||
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
for (Future<BluetoothSocket> f : futures) {
|
for (Future<BluetoothSocket> f : futures) {
|
||||||
try {
|
try {
|
||||||
@@ -413,9 +431,7 @@ class DroidtoothPlugin implements DuplexPlugin {
|
|||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
LOG.info("Interrupted while closing sockets");
|
LOG.info("Interrupted while closing sockets");
|
||||||
return;
|
return;
|
||||||
} catch (ExecutionException e) {
|
} catch (ExecutionException | IOException e) {
|
||||||
if (LOG.isLoggable(INFO)) LOG.info(e.toString());
|
|
||||||
} catch (IOException e) {
|
|
||||||
if (LOG.isLoggable(INFO)) LOG.info(e.toString());
|
if (LOG.isLoggable(INFO)) LOG.info(e.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -423,14 +439,15 @@ class DroidtoothPlugin implements DuplexPlugin {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public boolean supportsKeyAgreement() {
|
public boolean supportsKeyAgreement() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public KeyAgreementListener createKeyAgreementListener(
|
@Override
|
||||||
byte[] localCommitment) {
|
public KeyAgreementListener createKeyAgreementListener(byte[] commitment) {
|
||||||
// No truncation necessary because COMMIT_LENGTH = 16
|
// No truncation necessary because COMMIT_LENGTH = 16
|
||||||
UUID uuid = UUID.nameUUIDFromBytes(localCommitment);
|
UUID uuid = UUID.nameUUIDFromBytes(commitment);
|
||||||
if (LOG.isLoggable(INFO)) LOG.info("Key agreement UUID " + uuid);
|
if (LOG.isLoggable(INFO)) LOG.info("Key agreement UUID " + uuid);
|
||||||
// Bind a server socket for receiving invitation connections
|
// Bind a server socket for receiving invitation connections
|
||||||
BluetoothServerSocket ss;
|
BluetoothServerSocket ss;
|
||||||
@@ -448,8 +465,9 @@ class DroidtoothPlugin implements DuplexPlugin {
|
|||||||
return new BluetoothKeyAgreementListener(d, ss);
|
return new BluetoothKeyAgreementListener(d, ss);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public DuplexTransportConnection createKeyAgreementConnection(
|
public DuplexTransportConnection createKeyAgreementConnection(
|
||||||
byte[] remoteCommitment, TransportDescriptor d, long timeout) {
|
byte[] commitment, TransportDescriptor d, long timeout) {
|
||||||
if (!isRunning()) return null;
|
if (!isRunning()) return null;
|
||||||
if (!ID.equals(d.getIdentifier())) return null;
|
if (!ID.equals(d.getIdentifier())) return null;
|
||||||
TransportProperties p = d.getProperties();
|
TransportProperties p = d.getProperties();
|
||||||
@@ -457,7 +475,7 @@ class DroidtoothPlugin implements DuplexPlugin {
|
|||||||
String address = p.get(PROP_ADDRESS);
|
String address = p.get(PROP_ADDRESS);
|
||||||
if (StringUtils.isNullOrEmpty(address)) return null;
|
if (StringUtils.isNullOrEmpty(address)) return null;
|
||||||
// No truncation necessary because COMMIT_LENGTH = 16
|
// No truncation necessary because COMMIT_LENGTH = 16
|
||||||
UUID uuid = UUID.nameUUIDFromBytes(remoteCommitment);
|
UUID uuid = UUID.nameUUIDFromBytes(commitment);
|
||||||
if (LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
LOG.info("Connecting to key agreement UUID " + uuid);
|
LOG.info("Connecting to key agreement UUID " + uuid);
|
||||||
BluetoothSocket s = connect(address, uuid.toString());
|
BluetoothSocket s = connect(address, uuid.toString());
|
||||||
@@ -533,7 +551,7 @@ class DroidtoothPlugin implements DuplexPlugin {
|
|||||||
private static class DiscoveryReceiver extends BroadcastReceiver {
|
private static class DiscoveryReceiver extends BroadcastReceiver {
|
||||||
|
|
||||||
private final CountDownLatch finished = new CountDownLatch(1);
|
private final CountDownLatch finished = new CountDownLatch(1);
|
||||||
private final List<String> addresses = new ArrayList<String>();
|
private final List<String> addresses = new ArrayList<>();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onReceive(Context ctx, Intent intent) {
|
public void onReceive(Context ctx, Intent intent) {
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ class AndroidLanTcpPlugin extends LanTcpPlugin {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean start() {
|
public boolean start() {
|
||||||
|
if (used.getAndSet(true)) throw new IllegalStateException();
|
||||||
running = true;
|
running = true;
|
||||||
// Register to receive network status events
|
// Register to receive network status events
|
||||||
networkStateReceiver = new NetworkStateReceiver();
|
networkStateReceiver = new NetworkStateReceiver();
|
||||||
|
|||||||
@@ -51,6 +51,7 @@ import java.util.Map;
|
|||||||
import java.util.Scanner;
|
import java.util.Scanner;
|
||||||
import java.util.concurrent.CountDownLatch;
|
import java.util.concurrent.CountDownLatch;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
import java.util.zip.ZipInputStream;
|
import java.util.zip.ZipInputStream;
|
||||||
@@ -94,6 +95,7 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
|||||||
private final File torDirectory, torFile, geoIpFile, configFile;
|
private final File torDirectory, torFile, geoIpFile, configFile;
|
||||||
private final File doneFile, cookieFile;
|
private final File doneFile, cookieFile;
|
||||||
private final PowerManager.WakeLock wakeLock;
|
private final PowerManager.WakeLock wakeLock;
|
||||||
|
private final AtomicBoolean used = new AtomicBoolean(false);
|
||||||
|
|
||||||
private volatile boolean running = false;
|
private volatile boolean running = false;
|
||||||
private volatile ServerSocket socket = null;
|
private volatile ServerSocket socket = null;
|
||||||
@@ -130,19 +132,24 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
|||||||
wakeLock.setReferenceCounted(false);
|
wakeLock.setReferenceCounted(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public TransportId getId() {
|
public TransportId getId() {
|
||||||
return ID;
|
return ID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public int getMaxLatency() {
|
public int getMaxLatency() {
|
||||||
return maxLatency;
|
return maxLatency;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public int getMaxIdleTime() {
|
public int getMaxIdleTime() {
|
||||||
return maxIdleTime;
|
return maxIdleTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public boolean start() throws IOException {
|
public boolean start() throws IOException {
|
||||||
|
if (used.getAndSet(true)) throw new IllegalStateException();
|
||||||
// Try to connect to an existing Tor process if there is one
|
// Try to connect to an existing Tor process if there is one
|
||||||
boolean startProcess = false;
|
boolean startProcess = false;
|
||||||
try {
|
try {
|
||||||
@@ -210,13 +217,13 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
|||||||
// Now we should be able to connect to the new process
|
// Now we should be able to connect to the new process
|
||||||
controlSocket = new Socket("127.0.0.1", CONTROL_PORT);
|
controlSocket = new Socket("127.0.0.1", CONTROL_PORT);
|
||||||
}
|
}
|
||||||
running = true;
|
|
||||||
// Open a control connection and authenticate using the cookie file
|
// Open a control connection and authenticate using the cookie file
|
||||||
controlConnection = new TorControlConnection(controlSocket);
|
controlConnection = new TorControlConnection(controlSocket);
|
||||||
controlConnection.authenticate(read(cookieFile));
|
controlConnection.authenticate(read(cookieFile));
|
||||||
// Tell Tor to exit when the control connection is closed
|
// Tell Tor to exit when the control connection is closed
|
||||||
controlConnection.takeOwnership();
|
controlConnection.takeOwnership();
|
||||||
controlConnection.resetConf(Collections.singletonList(OWNER));
|
controlConnection.resetConf(Collections.singletonList(OWNER));
|
||||||
|
running = true;
|
||||||
// Register to receive events from the Tor process
|
// Register to receive events from the Tor process
|
||||||
controlConnection.setEventHandler(this);
|
controlConnection.setEventHandler(this);
|
||||||
controlConnection.setEvents(Arrays.asList(EVENTS));
|
controlConnection.setEvents(Arrays.asList(EVENTS));
|
||||||
@@ -226,7 +233,6 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
|||||||
if (phase != null && phase.contains("PROGRESS=100")) {
|
if (phase != null && phase.contains("PROGRESS=100")) {
|
||||||
LOG.info("Tor has already bootstrapped");
|
LOG.info("Tor has already bootstrapped");
|
||||||
connectionStatus.setBootstrapped();
|
connectionStatus.setBootstrapped();
|
||||||
sendDevReports();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Register to receive network status events
|
// Register to receive network status events
|
||||||
@@ -369,6 +375,7 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
|||||||
|
|
||||||
private void bind() {
|
private void bind() {
|
||||||
ioExecutor.execute(new Runnable() {
|
ioExecutor.execute(new Runnable() {
|
||||||
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
// If there's already a port number stored in config, reuse it
|
// If there's already a port number stored in config, reuse it
|
||||||
String portString = callback.getSettings().get("port");
|
String portString = callback.getSettings().get("port");
|
||||||
@@ -398,6 +405,7 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
|||||||
callback.mergeSettings(s);
|
callback.mergeSettings(s);
|
||||||
// Create a hidden service if necessary
|
// Create a hidden service if necessary
|
||||||
ioExecutor.execute(new Runnable() {
|
ioExecutor.execute(new Runnable() {
|
||||||
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
publishHiddenService(localPort);
|
publishHiddenService(localPort);
|
||||||
}
|
}
|
||||||
@@ -486,6 +494,7 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void stop() throws IOException {
|
public void stop() throws IOException {
|
||||||
running = false;
|
running = false;
|
||||||
tryToClose(socket);
|
tryToClose(socket);
|
||||||
@@ -508,18 +517,22 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
|||||||
wakeLock.release();
|
wakeLock.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public boolean isRunning() {
|
public boolean isRunning() {
|
||||||
return running && connectionStatus.isConnected();
|
return running && connectionStatus.isConnected();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public boolean shouldPoll() {
|
public boolean shouldPoll() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public int getPollingInterval() {
|
public int getPollingInterval() {
|
||||||
return backoff.getPollingInterval();
|
return backoff.getPollingInterval();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void poll(Collection<ContactId> connected) {
|
public void poll(Collection<ContactId> connected) {
|
||||||
if (!isRunning()) return;
|
if (!isRunning()) return;
|
||||||
backoff.increment();
|
backoff.increment();
|
||||||
@@ -530,6 +543,7 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
|||||||
|
|
||||||
private void connectAndCallBack(final ContactId c) {
|
private void connectAndCallBack(final ContactId c) {
|
||||||
ioExecutor.execute(new Runnable() {
|
ioExecutor.execute(new Runnable() {
|
||||||
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
DuplexTransportConnection d = createConnection(c);
|
DuplexTransportConnection d = createConnection(c);
|
||||||
if (d != null) {
|
if (d != null) {
|
||||||
@@ -540,6 +554,7 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public DuplexTransportConnection createConnection(ContactId c) {
|
public DuplexTransportConnection createConnection(ContactId c) {
|
||||||
if (!isRunning()) return null;
|
if (!isRunning()) return null;
|
||||||
TransportProperties p = callback.getRemoteProperties().get(c);
|
TransportProperties p = callback.getRemoteProperties().get(c);
|
||||||
@@ -566,61 +581,77 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public boolean supportsInvitations() {
|
public boolean supportsInvitations() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public DuplexTransportConnection createInvitationConnection(PseudoRandom r,
|
public DuplexTransportConnection createInvitationConnection(PseudoRandom r,
|
||||||
long timeout, boolean alice) {
|
long timeout, boolean alice) {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public boolean supportsKeyAgreement() {
|
public boolean supportsKeyAgreement() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public KeyAgreementListener createKeyAgreementListener(
|
@Override
|
||||||
byte[] commitment) {
|
public KeyAgreementListener createKeyAgreementListener(byte[] commitment) {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public DuplexTransportConnection createKeyAgreementConnection(
|
public DuplexTransportConnection createKeyAgreementConnection(
|
||||||
byte[] commitment, TransportDescriptor d, long timeout) {
|
byte[] commitment, TransportDescriptor d, long timeout) {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void circuitStatus(String status, String id, String path) {
|
public void circuitStatus(String status, String id, String path) {
|
||||||
if (status.equals("BUILT") &&
|
if (status.equals("BUILT") &&
|
||||||
connectionStatus.getAndSetCircuitBuilt()) {
|
connectionStatus.getAndSetCircuitBuilt()) {
|
||||||
LOG.info("First circuit built");
|
LOG.info("First circuit built");
|
||||||
backoff.reset();
|
backoff.reset();
|
||||||
if (isRunning()) callback.transportEnabled();
|
if (isRunning()) {
|
||||||
|
sendDevReports();
|
||||||
|
callback.transportEnabled();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void streamStatus(String status, String id, String target) {
|
public void streamStatus(String status, String id, String target) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void orConnStatus(String status, String orName) {
|
public void orConnStatus(String status, String orName) {
|
||||||
if (LOG.isLoggable(INFO)) LOG.info("OR connection " + status);
|
if (LOG.isLoggable(INFO)) LOG.info("OR connection " + status);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void bandwidthUsed(long read, long written) {
|
public void bandwidthUsed(long read, long written) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void newDescriptors(List<String> orList) {
|
public void newDescriptors(List<String> orList) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void message(String severity, String msg) {
|
public void message(String severity, String msg) {
|
||||||
if (LOG.isLoggable(INFO)) LOG.info(severity + " " + msg);
|
if (LOG.isLoggable(INFO)) LOG.info(severity + " " + msg);
|
||||||
if (severity.equals("NOTICE") && msg.startsWith("Bootstrapped 100%")) {
|
if (severity.equals("NOTICE") && msg.startsWith("Bootstrapped 100%")) {
|
||||||
connectionStatus.setBootstrapped();
|
connectionStatus.setBootstrapped();
|
||||||
sendDevReports();
|
|
||||||
backoff.reset();
|
backoff.reset();
|
||||||
if (isRunning()) callback.transportEnabled();
|
if (isRunning()) {
|
||||||
|
sendDevReports();
|
||||||
|
callback.transportEnabled();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void unrecognized(String type, String msg) {
|
public void unrecognized(String type, String msg) {
|
||||||
if (type.equals("HS_DESC") && msg.startsWith("UPLOADED"))
|
if (type.equals("HS_DESC") && msg.startsWith("UPLOADED"))
|
||||||
LOG.info("Descriptor uploaded");
|
LOG.info("Descriptor uploaded");
|
||||||
@@ -642,6 +673,7 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void eventOccurred(Event e) {
|
public void eventOccurred(Event e) {
|
||||||
if (e instanceof SettingsUpdatedEvent) {
|
if (e instanceof SettingsUpdatedEvent) {
|
||||||
if (((SettingsUpdatedEvent) e).getNamespace().equals("tor")) {
|
if (((SettingsUpdatedEvent) e).getNamespace().equals("tor")) {
|
||||||
@@ -653,13 +685,14 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
|||||||
|
|
||||||
private void updateConnectionStatus() {
|
private void updateConnectionStatus() {
|
||||||
ioExecutor.execute(new Runnable() {
|
ioExecutor.execute(new Runnable() {
|
||||||
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
if (!running) return;
|
if (!running) return;
|
||||||
|
|
||||||
Object o = appContext.getSystemService(CONNECTIVITY_SERVICE);
|
Object o = appContext.getSystemService(CONNECTIVITY_SERVICE);
|
||||||
ConnectivityManager cm = (ConnectivityManager) o;
|
ConnectivityManager cm = (ConnectivityManager) o;
|
||||||
NetworkInfo net = cm.getActiveNetworkInfo();
|
NetworkInfo net = cm.getActiveNetworkInfo();
|
||||||
boolean online = net != null && net.isConnected();
|
boolean online = net != null && net.isConnected();
|
||||||
boolean wifi = online && net.getType() == TYPE_WIFI;
|
boolean wifi = online && net.getType() == TYPE_WIFI;
|
||||||
String country = locationUtils.getCurrentCountry();
|
String country = locationUtils.getCurrentCountry();
|
||||||
boolean blocked = TorNetworkMetadata.isTorProbablyBlocked(
|
boolean blocked = TorNetworkMetadata.isTorProbablyBlocked(
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package org.briarproject.api.reporting;
|
|||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A task for reporting back to the developers.
|
* A task for reporting back to the developers.
|
||||||
|
|||||||
@@ -53,20 +53,20 @@ class LifecycleManagerImpl implements LifecycleManager {
|
|||||||
@Override
|
@Override
|
||||||
public void registerService(Service s) {
|
public void registerService(Service s) {
|
||||||
if (LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
LOG.info("Registering service " + s.getClass().getName());
|
LOG.info("Registering service " + s.getClass().getSimpleName());
|
||||||
services.add(s);
|
services.add(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void registerClient(Client c) {
|
public void registerClient(Client c) {
|
||||||
if (LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
LOG.info("Registering client " + c.getClass().getName());
|
LOG.info("Registering client " + c.getClass().getSimpleName());
|
||||||
clients.add(c);
|
clients.add(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void registerForShutdown(ExecutorService e) {
|
public void registerForShutdown(ExecutorService e) {
|
||||||
LOG.info("Registering executor");
|
LOG.info("Registering executor " + e.getClass().getSimpleName());
|
||||||
executors.add(e);
|
executors.add(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -94,7 +94,8 @@ class LifecycleManagerImpl implements LifecycleManager {
|
|||||||
c.createLocalState(txn);
|
c.createLocalState(txn);
|
||||||
duration = System.currentTimeMillis() - start;
|
duration = System.currentTimeMillis() - start;
|
||||||
if (LOG.isLoggable(INFO)) {
|
if (LOG.isLoggable(INFO)) {
|
||||||
LOG.info("Starting client " + c.getClass().getName()
|
LOG.info("Starting client "
|
||||||
|
+ c.getClass().getSimpleName()
|
||||||
+ " took " + duration + " ms");
|
+ " took " + duration + " ms");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -107,7 +108,7 @@ class LifecycleManagerImpl implements LifecycleManager {
|
|||||||
s.startService();
|
s.startService();
|
||||||
duration = System.currentTimeMillis() - start;
|
duration = System.currentTimeMillis() - start;
|
||||||
if (LOG.isLoggable(INFO)) {
|
if (LOG.isLoggable(INFO)) {
|
||||||
LOG.info("Starting service " + s.getClass().getName()
|
LOG.info("Starting service " + s.getClass().getSimpleName()
|
||||||
+ " took " + duration + " ms");
|
+ " took " + duration + " ms");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -140,13 +141,17 @@ class LifecycleManagerImpl implements LifecycleManager {
|
|||||||
s.stopService();
|
s.stopService();
|
||||||
long duration = System.currentTimeMillis() - start;
|
long duration = System.currentTimeMillis() - start;
|
||||||
if (LOG.isLoggable(INFO)) {
|
if (LOG.isLoggable(INFO)) {
|
||||||
LOG.info("Stopping service " + s.getClass().getName()
|
LOG.info("Stopping service " + s.getClass().getSimpleName()
|
||||||
+ " took " + duration + " ms");
|
+ " took " + duration + " ms");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (ExecutorService e : executors) e.shutdownNow();
|
for (ExecutorService e : executors) {
|
||||||
if (LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO)) {
|
||||||
LOG.info(executors.size() + " executors shut down");
|
LOG.info("Stopping executor "
|
||||||
|
+ e.getClass().getSimpleName());
|
||||||
|
}
|
||||||
|
e.shutdownNow();
|
||||||
|
}
|
||||||
long start = System.currentTimeMillis();
|
long start = System.currentTimeMillis();
|
||||||
db.close();
|
db.close();
|
||||||
long duration = System.currentTimeMillis() - start;
|
long duration = System.currentTimeMillis() - start;
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ import java.util.concurrent.ConcurrentHashMap;
|
|||||||
import java.util.concurrent.CopyOnWriteArrayList;
|
import java.util.concurrent.CopyOnWriteArrayList;
|
||||||
import java.util.concurrent.CountDownLatch;
|
import java.util.concurrent.CountDownLatch;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
@@ -61,6 +62,8 @@ class PluginManagerImpl implements PluginManager, Service {
|
|||||||
private final Map<TransportId, Plugin> plugins;
|
private final Map<TransportId, Plugin> plugins;
|
||||||
private final List<SimplexPlugin> simplexPlugins;
|
private final List<SimplexPlugin> simplexPlugins;
|
||||||
private final List<DuplexPlugin> duplexPlugins;
|
private final List<DuplexPlugin> duplexPlugins;
|
||||||
|
private final Map<TransportId, CountDownLatch> startLatches;
|
||||||
|
private final AtomicBoolean used = new AtomicBoolean(false);
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
PluginManagerImpl(@IoExecutor Executor ioExecutor, EventBus eventBus,
|
PluginManagerImpl(@IoExecutor Executor ioExecutor, EventBus eventBus,
|
||||||
@@ -78,68 +81,64 @@ class PluginManagerImpl implements PluginManager, Service {
|
|||||||
plugins = new ConcurrentHashMap<TransportId, Plugin>();
|
plugins = new ConcurrentHashMap<TransportId, Plugin>();
|
||||||
simplexPlugins = new CopyOnWriteArrayList<SimplexPlugin>();
|
simplexPlugins = new CopyOnWriteArrayList<SimplexPlugin>();
|
||||||
duplexPlugins = new CopyOnWriteArrayList<DuplexPlugin>();
|
duplexPlugins = new CopyOnWriteArrayList<DuplexPlugin>();
|
||||||
|
startLatches = new ConcurrentHashMap<TransportId, CountDownLatch>();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void startService() throws ServiceException {
|
public void startService() throws ServiceException {
|
||||||
Collection<SimplexPluginFactory> simplexFactories =
|
if (used.getAndSet(true)) throw new IllegalStateException();
|
||||||
pluginConfig.getSimplexFactories();
|
// Instantiate the simplex plugins and start them asynchronously
|
||||||
Collection<DuplexPluginFactory> duplexFactories =
|
|
||||||
pluginConfig.getDuplexFactories();
|
|
||||||
int numPlugins = simplexFactories.size() + duplexFactories.size();
|
|
||||||
CountDownLatch latch = new CountDownLatch(numPlugins);
|
|
||||||
// Instantiate and start the simplex plugins
|
|
||||||
LOG.info("Starting simplex plugins");
|
LOG.info("Starting simplex plugins");
|
||||||
for (SimplexPluginFactory f : simplexFactories) {
|
for (SimplexPluginFactory f : pluginConfig.getSimplexFactories()) {
|
||||||
TransportId t = f.getId();
|
TransportId t = f.getId();
|
||||||
SimplexPlugin s = f.createPlugin(new SimplexCallback(t));
|
SimplexPlugin s = f.createPlugin(new SimplexCallback(t));
|
||||||
if (s == null) {
|
if (s == null) {
|
||||||
if (LOG.isLoggable(WARNING))
|
if (LOG.isLoggable(WARNING))
|
||||||
LOG.warning("Could not create plugin for " + t);
|
LOG.warning("Could not create plugin for " + t);
|
||||||
latch.countDown();
|
|
||||||
} else {
|
} else {
|
||||||
plugins.put(t, s);
|
plugins.put(t, s);
|
||||||
simplexPlugins.add(s);
|
simplexPlugins.add(s);
|
||||||
ioExecutor.execute(new PluginStarter(s, latch));
|
CountDownLatch startLatch = new CountDownLatch(1);
|
||||||
|
startLatches.put(t, startLatch);
|
||||||
|
ioExecutor.execute(new PluginStarter(s, startLatch));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Instantiate and start the duplex plugins
|
// Instantiate the duplex plugins and start them asynchronously
|
||||||
LOG.info("Starting duplex plugins");
|
LOG.info("Starting duplex plugins");
|
||||||
for (DuplexPluginFactory f : duplexFactories) {
|
for (DuplexPluginFactory f : pluginConfig.getDuplexFactories()) {
|
||||||
TransportId t = f.getId();
|
TransportId t = f.getId();
|
||||||
DuplexPlugin d = f.createPlugin(new DuplexCallback(t));
|
DuplexPlugin d = f.createPlugin(new DuplexCallback(t));
|
||||||
if (d == null) {
|
if (d == null) {
|
||||||
if (LOG.isLoggable(WARNING))
|
if (LOG.isLoggable(WARNING))
|
||||||
LOG.warning("Could not create plugin for " + t);
|
LOG.warning("Could not create plugin for " + t);
|
||||||
latch.countDown();
|
|
||||||
} else {
|
} else {
|
||||||
plugins.put(t, d);
|
plugins.put(t, d);
|
||||||
duplexPlugins.add(d);
|
duplexPlugins.add(d);
|
||||||
ioExecutor.execute(new PluginStarter(d, latch));
|
CountDownLatch startLatch = new CountDownLatch(1);
|
||||||
|
startLatches.put(t, startLatch);
|
||||||
|
ioExecutor.execute(new PluginStarter(d, startLatch));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Wait for all the plugins to start
|
|
||||||
try {
|
|
||||||
latch.await();
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
throw new ServiceException(e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void stopService() throws ServiceException {
|
public void stopService() throws ServiceException {
|
||||||
CountDownLatch latch = new CountDownLatch(plugins.size());
|
CountDownLatch stopLatch = new CountDownLatch(plugins.size());
|
||||||
// Stop the simplex plugins
|
// Stop the simplex plugins
|
||||||
LOG.info("Stopping simplex plugins");
|
LOG.info("Stopping simplex plugins");
|
||||||
for (SimplexPlugin plugin : simplexPlugins)
|
for (SimplexPlugin s : simplexPlugins) {
|
||||||
ioExecutor.execute(new PluginStopper(plugin, latch));
|
CountDownLatch startLatch = startLatches.get(s.getId());
|
||||||
|
ioExecutor.execute(new PluginStopper(s, startLatch, stopLatch));
|
||||||
|
}
|
||||||
// Stop the duplex plugins
|
// Stop the duplex plugins
|
||||||
LOG.info("Stopping duplex plugins");
|
LOG.info("Stopping duplex plugins");
|
||||||
for (DuplexPlugin plugin : duplexPlugins)
|
for (DuplexPlugin d : duplexPlugins) {
|
||||||
ioExecutor.execute(new PluginStopper(plugin, latch));
|
CountDownLatch startLatch = startLatches.get(d.getId());
|
||||||
|
ioExecutor.execute(new PluginStopper(d, startLatch, stopLatch));
|
||||||
|
}
|
||||||
// Wait for all the plugins to stop
|
// Wait for all the plugins to stop
|
||||||
try {
|
try {
|
||||||
latch.await();
|
stopLatch.await();
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
throw new ServiceException(e);
|
throw new ServiceException(e);
|
||||||
}
|
}
|
||||||
@@ -179,11 +178,11 @@ class PluginManagerImpl implements PluginManager, Service {
|
|||||||
private class PluginStarter implements Runnable {
|
private class PluginStarter implements Runnable {
|
||||||
|
|
||||||
private final Plugin plugin;
|
private final Plugin plugin;
|
||||||
private final CountDownLatch latch;
|
private final CountDownLatch startLatch;
|
||||||
|
|
||||||
private PluginStarter(Plugin plugin, CountDownLatch latch) {
|
private PluginStarter(Plugin plugin, CountDownLatch startLatch) {
|
||||||
this.plugin = plugin;
|
this.plugin = plugin;
|
||||||
this.latch = latch;
|
this.startLatch = startLatch;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -209,7 +208,7 @@ class PluginManagerImpl implements PluginManager, Service {
|
|||||||
LOG.log(WARNING, e.toString(), e);
|
LOG.log(WARNING, e.toString(), e);
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
latch.countDown();
|
startLatch.countDown();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -217,16 +216,21 @@ class PluginManagerImpl implements PluginManager, Service {
|
|||||||
private class PluginStopper implements Runnable {
|
private class PluginStopper implements Runnable {
|
||||||
|
|
||||||
private final Plugin plugin;
|
private final Plugin plugin;
|
||||||
private final CountDownLatch latch;
|
private final CountDownLatch startLatch, stopLatch;
|
||||||
|
|
||||||
private PluginStopper(Plugin plugin, CountDownLatch latch) {
|
private PluginStopper(Plugin plugin, CountDownLatch startLatch,
|
||||||
|
CountDownLatch stopLatch) {
|
||||||
this.plugin = plugin;
|
this.plugin = plugin;
|
||||||
this.latch = latch;
|
this.startLatch = startLatch;
|
||||||
|
this.stopLatch = stopLatch;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
|
// Wait for the plugin to finish starting
|
||||||
|
startLatch.await();
|
||||||
|
// Stop the plugin
|
||||||
long start = System.currentTimeMillis();
|
long start = System.currentTimeMillis();
|
||||||
plugin.stop();
|
plugin.stop();
|
||||||
long duration = System.currentTimeMillis() - start;
|
long duration = System.currentTimeMillis() - start;
|
||||||
@@ -234,10 +238,13 @@ class PluginManagerImpl implements PluginManager, Service {
|
|||||||
LOG.info("Stopping plugin " + plugin.getId()
|
LOG.info("Stopping plugin " + plugin.getId()
|
||||||
+ " took " + duration + " ms");
|
+ " took " + duration + " ms");
|
||||||
}
|
}
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
LOG.warning("Interrupted while waiting for plugin to start");
|
||||||
|
// This task runs on an executor, so don't reset the interrupt
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||||
} finally {
|
} finally {
|
||||||
latch.countDown();
|
stopLatch.countDown();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import java.io.OutputStream;
|
|||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
@@ -27,6 +28,7 @@ public abstract class FilePlugin implements SimplexPlugin {
|
|||||||
protected final Executor ioExecutor;
|
protected final Executor ioExecutor;
|
||||||
protected final SimplexPluginCallback callback;
|
protected final SimplexPluginCallback callback;
|
||||||
protected final int maxLatency;
|
protected final int maxLatency;
|
||||||
|
protected final AtomicBoolean used = new AtomicBoolean(false);
|
||||||
|
|
||||||
protected volatile boolean running = false;
|
protected volatile boolean running = false;
|
||||||
|
|
||||||
@@ -42,22 +44,27 @@ public abstract class FilePlugin implements SimplexPlugin {
|
|||||||
this.maxLatency = maxLatency;
|
this.maxLatency = maxLatency;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public int getMaxLatency() {
|
public int getMaxLatency() {
|
||||||
return maxLatency;
|
return maxLatency;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public int getMaxIdleTime() {
|
public int getMaxIdleTime() {
|
||||||
return Integer.MAX_VALUE; // We don't need keepalives
|
return Integer.MAX_VALUE; // We don't need keepalives
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public boolean isRunning() {
|
public boolean isRunning() {
|
||||||
return running;
|
return running;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public TransportConnectionReader createReader(ContactId c) {
|
public TransportConnectionReader createReader(ContactId c) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public TransportConnectionWriter createWriter(ContactId c) {
|
public TransportConnectionWriter createWriter(ContactId c) {
|
||||||
if (!running) return null;
|
if (!running) return null;
|
||||||
return createWriter(createConnectionFilename());
|
return createWriter(createConnectionFilename());
|
||||||
@@ -105,6 +112,7 @@ public abstract class FilePlugin implements SimplexPlugin {
|
|||||||
this.file = file;
|
this.file = file;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
if (isPossibleConnectionFilename(file.getName())) {
|
if (isPossibleConnectionFilename(file.getName())) {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ class LanTcpPlugin extends TcpPlugin {
|
|||||||
super(ioExecutor, backoff, callback, maxLatency, maxIdleTime);
|
super(ioExecutor, backoff, callback, maxLatency, maxIdleTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public TransportId getId() {
|
public TransportId getId() {
|
||||||
return ID;
|
return ID;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import java.util.Collection;
|
|||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
@@ -41,6 +42,7 @@ abstract class TcpPlugin implements DuplexPlugin {
|
|||||||
protected final Backoff backoff;
|
protected final Backoff backoff;
|
||||||
protected final DuplexPluginCallback callback;
|
protected final DuplexPluginCallback callback;
|
||||||
protected final int maxLatency, maxIdleTime, socketTimeout;
|
protected final int maxLatency, maxIdleTime, socketTimeout;
|
||||||
|
protected final AtomicBoolean used = new AtomicBoolean(false);
|
||||||
|
|
||||||
protected volatile boolean running = false;
|
protected volatile boolean running = false;
|
||||||
protected volatile ServerSocket socket = null;
|
protected volatile ServerSocket socket = null;
|
||||||
@@ -81,15 +83,19 @@ abstract class TcpPlugin implements DuplexPlugin {
|
|||||||
else socketTimeout = maxIdleTime * 2;
|
else socketTimeout = maxIdleTime * 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public int getMaxLatency() {
|
public int getMaxLatency() {
|
||||||
return maxLatency;
|
return maxLatency;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public int getMaxIdleTime() {
|
public int getMaxIdleTime() {
|
||||||
return maxIdleTime;
|
return maxIdleTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public boolean start() {
|
public boolean start() {
|
||||||
|
if (used.getAndSet(true)) throw new IllegalStateException();
|
||||||
running = true;
|
running = true;
|
||||||
bind();
|
bind();
|
||||||
return true;
|
return true;
|
||||||
@@ -97,6 +103,7 @@ abstract class TcpPlugin implements DuplexPlugin {
|
|||||||
|
|
||||||
protected void bind() {
|
protected void bind() {
|
||||||
ioExecutor.execute(new Runnable() {
|
ioExecutor.execute(new Runnable() {
|
||||||
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
if (!running) return;
|
if (!running) return;
|
||||||
ServerSocket ss = null;
|
ServerSocket ss = null;
|
||||||
@@ -166,23 +173,28 @@ abstract class TcpPlugin implements DuplexPlugin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void stop() {
|
public void stop() {
|
||||||
running = false;
|
running = false;
|
||||||
tryToClose(socket);
|
tryToClose(socket);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public boolean isRunning() {
|
public boolean isRunning() {
|
||||||
return running && socket != null && !socket.isClosed();
|
return running && socket != null && !socket.isClosed();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public boolean shouldPoll() {
|
public boolean shouldPoll() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public int getPollingInterval() {
|
public int getPollingInterval() {
|
||||||
return backoff.getPollingInterval();
|
return backoff.getPollingInterval();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void poll(Collection<ContactId> connected) {
|
public void poll(Collection<ContactId> connected) {
|
||||||
if (!isRunning()) return;
|
if (!isRunning()) return;
|
||||||
backoff.increment();
|
backoff.increment();
|
||||||
@@ -193,6 +205,7 @@ abstract class TcpPlugin implements DuplexPlugin {
|
|||||||
|
|
||||||
private void connectAndCallBack(final ContactId c) {
|
private void connectAndCallBack(final ContactId c) {
|
||||||
ioExecutor.execute(new Runnable() {
|
ioExecutor.execute(new Runnable() {
|
||||||
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
DuplexTransportConnection d = createConnection(c);
|
DuplexTransportConnection d = createConnection(c);
|
||||||
if (d != null) {
|
if (d != null) {
|
||||||
@@ -203,6 +216,7 @@ abstract class TcpPlugin implements DuplexPlugin {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public DuplexTransportConnection createConnection(ContactId c) {
|
public DuplexTransportConnection createConnection(ContactId c) {
|
||||||
if (!isRunning()) return null;
|
if (!isRunning()) return null;
|
||||||
for (InetSocketAddress remote : getRemoteSocketAddresses(c)) {
|
for (InetSocketAddress remote : getRemoteSocketAddresses(c)) {
|
||||||
@@ -250,24 +264,28 @@ abstract class TcpPlugin implements DuplexPlugin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public boolean supportsInvitations() {
|
public boolean supportsInvitations() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public DuplexTransportConnection createInvitationConnection(PseudoRandom r,
|
public DuplexTransportConnection createInvitationConnection(PseudoRandom r,
|
||||||
long timeout, boolean alice) {
|
long timeout, boolean alice) {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public boolean supportsKeyAgreement() {
|
public boolean supportsKeyAgreement() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public KeyAgreementListener createKeyAgreementListener(
|
@Override
|
||||||
byte[] commitment) {
|
public KeyAgreementListener createKeyAgreementListener(byte[] commitment) {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public DuplexTransportConnection createKeyAgreementConnection(
|
public DuplexTransportConnection createKeyAgreementConnection(
|
||||||
byte[] commitment, TransportDescriptor d, long timeout) {
|
byte[] commitment, TransportDescriptor d, long timeout) {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ class WanTcpPlugin extends TcpPlugin {
|
|||||||
this.portMapper = portMapper;
|
this.portMapper = portMapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public TransportId getId() {
|
public TransportId getId() {
|
||||||
return ID;
|
return ID;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ import java.util.Map;
|
|||||||
import java.util.Queue;
|
import java.util.Queue;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
@@ -44,6 +45,7 @@ class ValidationManagerImpl implements ValidationManager, Service,
|
|||||||
private final Executor cryptoExecutor;
|
private final Executor cryptoExecutor;
|
||||||
private final Map<ClientId, MessageValidator> validators;
|
private final Map<ClientId, MessageValidator> validators;
|
||||||
private final Map<ClientId, IncomingMessageHook> hooks;
|
private final Map<ClientId, IncomingMessageHook> hooks;
|
||||||
|
private final AtomicBoolean used = new AtomicBoolean(false);
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
ValidationManagerImpl(DatabaseComponent db,
|
ValidationManagerImpl(DatabaseComponent db,
|
||||||
@@ -58,6 +60,7 @@ class ValidationManagerImpl implements ValidationManager, Service,
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void startService() {
|
public void startService() {
|
||||||
|
if (used.getAndSet(true)) throw new IllegalStateException();
|
||||||
for (ClientId c : validators.keySet()) getMessagesToValidate(c);
|
for (ClientId c : validators.keySet()) getMessagesToValidate(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -78,6 +81,7 @@ class ValidationManagerImpl implements ValidationManager, Service,
|
|||||||
|
|
||||||
private void getMessagesToValidate(final ClientId c) {
|
private void getMessagesToValidate(final ClientId c) {
|
||||||
dbExecutor.execute(new Runnable() {
|
dbExecutor.execute(new Runnable() {
|
||||||
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
Queue<MessageId> unvalidated = new LinkedList<MessageId>();
|
Queue<MessageId> unvalidated = new LinkedList<MessageId>();
|
||||||
@@ -100,6 +104,7 @@ class ValidationManagerImpl implements ValidationManager, Service,
|
|||||||
private void validateNextMessage(final Queue<MessageId> unvalidated) {
|
private void validateNextMessage(final Queue<MessageId> unvalidated) {
|
||||||
if (unvalidated.isEmpty()) return;
|
if (unvalidated.isEmpty()) return;
|
||||||
dbExecutor.execute(new Runnable() {
|
dbExecutor.execute(new Runnable() {
|
||||||
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
Message m = null;
|
Message m = null;
|
||||||
@@ -141,6 +146,7 @@ class ValidationManagerImpl implements ValidationManager, Service,
|
|||||||
|
|
||||||
private void validateMessage(final Message m, final Group g) {
|
private void validateMessage(final Message m, final Group g) {
|
||||||
cryptoExecutor.execute(new Runnable() {
|
cryptoExecutor.execute(new Runnable() {
|
||||||
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
MessageValidator v = validators.get(g.getClientId());
|
MessageValidator v = validators.get(g.getClientId());
|
||||||
if (v == null) {
|
if (v == null) {
|
||||||
@@ -156,6 +162,7 @@ class ValidationManagerImpl implements ValidationManager, Service,
|
|||||||
private void storeValidationResult(final Message m, final ClientId c,
|
private void storeValidationResult(final Message m, final ClientId c,
|
||||||
final Metadata meta) {
|
final Metadata meta) {
|
||||||
dbExecutor.execute(new Runnable() {
|
dbExecutor.execute(new Runnable() {
|
||||||
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
Transaction txn = db.startTransaction(false);
|
Transaction txn = db.startTransaction(false);
|
||||||
@@ -193,6 +200,7 @@ class ValidationManagerImpl implements ValidationManager, Service,
|
|||||||
|
|
||||||
private void loadGroupAndValidate(final Message m) {
|
private void loadGroupAndValidate(final Message m) {
|
||||||
dbExecutor.execute(new Runnable() {
|
dbExecutor.execute(new Runnable() {
|
||||||
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
Group g;
|
Group g;
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ import java.util.Map.Entry;
|
|||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
import java.util.concurrent.ScheduledExecutorService;
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
@@ -47,6 +48,7 @@ class KeyManagerImpl implements KeyManager, Service, EventListener {
|
|||||||
private final Clock clock;
|
private final Clock clock;
|
||||||
private final Map<ContactId, Boolean> activeContacts;
|
private final Map<ContactId, Boolean> activeContacts;
|
||||||
private final ConcurrentHashMap<TransportId, TransportKeyManager> managers;
|
private final ConcurrentHashMap<TransportId, TransportKeyManager> managers;
|
||||||
|
private final AtomicBoolean used = new AtomicBoolean(false);
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
KeyManagerImpl(DatabaseComponent db, CryptoComponent crypto,
|
KeyManagerImpl(DatabaseComponent db, CryptoComponent crypto,
|
||||||
@@ -66,6 +68,7 @@ class KeyManagerImpl implements KeyManager, Service, EventListener {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void startService() throws ServiceException {
|
public void startService() throws ServiceException {
|
||||||
|
if (used.getAndSet(true)) throw new IllegalStateException();
|
||||||
Map<TransportId, Integer> transports =
|
Map<TransportId, Integer> transports =
|
||||||
new HashMap<TransportId, Integer>();
|
new HashMap<TransportId, Integer>();
|
||||||
for (SimplexPluginFactory f : pluginConfig.getSimplexFactories())
|
for (SimplexPluginFactory f : pluginConfig.getSimplexFactories())
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ import java.util.concurrent.Executor;
|
|||||||
import java.util.concurrent.ExecutorCompletionService;
|
import java.util.concurrent.ExecutorCompletionService;
|
||||||
import java.util.concurrent.Future;
|
import java.util.concurrent.Future;
|
||||||
import java.util.concurrent.Semaphore;
|
import java.util.concurrent.Semaphore;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import javax.bluetooth.BluetoothStateException;
|
import javax.bluetooth.BluetoothStateException;
|
||||||
@@ -62,6 +63,7 @@ class BluetoothPlugin implements DuplexPlugin {
|
|||||||
private final DuplexPluginCallback callback;
|
private final DuplexPluginCallback callback;
|
||||||
private final int maxLatency;
|
private final int maxLatency;
|
||||||
private final Semaphore discoverySemaphore = new Semaphore(1);
|
private final Semaphore discoverySemaphore = new Semaphore(1);
|
||||||
|
private final AtomicBoolean used = new AtomicBoolean(false);
|
||||||
|
|
||||||
private volatile boolean running = false;
|
private volatile boolean running = false;
|
||||||
private volatile StreamConnectionNotifier socket = null;
|
private volatile StreamConnectionNotifier socket = null;
|
||||||
@@ -76,20 +78,25 @@ class BluetoothPlugin implements DuplexPlugin {
|
|||||||
this.maxLatency = maxLatency;
|
this.maxLatency = maxLatency;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public TransportId getId() {
|
public TransportId getId() {
|
||||||
return ID;
|
return ID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public int getMaxLatency() {
|
public int getMaxLatency() {
|
||||||
return maxLatency;
|
return maxLatency;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public int getMaxIdleTime() {
|
public int getMaxIdleTime() {
|
||||||
// Bluetooth detects dead connections so we don't need keepalives
|
// Bluetooth detects dead connections so we don't need keepalives
|
||||||
return Integer.MAX_VALUE;
|
return Integer.MAX_VALUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public boolean start() throws IOException {
|
public boolean start() throws IOException {
|
||||||
|
if (used.getAndSet(true)) throw new IllegalStateException();
|
||||||
// Initialise the Bluetooth stack
|
// Initialise the Bluetooth stack
|
||||||
try {
|
try {
|
||||||
localDevice = LocalDevice.getLocalDevice();
|
localDevice = LocalDevice.getLocalDevice();
|
||||||
@@ -108,6 +115,7 @@ class BluetoothPlugin implements DuplexPlugin {
|
|||||||
|
|
||||||
private void bind() {
|
private void bind() {
|
||||||
ioExecutor.execute(new Runnable() {
|
ioExecutor.execute(new Runnable() {
|
||||||
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
if (!running) return;
|
if (!running) return;
|
||||||
// Advertise the Bluetooth address to contacts
|
// Advertise the Bluetooth address to contacts
|
||||||
@@ -183,23 +191,28 @@ class BluetoothPlugin implements DuplexPlugin {
|
|||||||
return new BluetoothTransportConnection(this, s);
|
return new BluetoothTransportConnection(this, s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void stop() {
|
public void stop() {
|
||||||
running = false;
|
running = false;
|
||||||
tryToClose(socket);
|
tryToClose(socket);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public boolean isRunning() {
|
public boolean isRunning() {
|
||||||
return running;
|
return running;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public boolean shouldPoll() {
|
public boolean shouldPoll() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public int getPollingInterval() {
|
public int getPollingInterval() {
|
||||||
return backoff.getPollingInterval();
|
return backoff.getPollingInterval();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void poll(final Collection<ContactId> connected) {
|
public void poll(final Collection<ContactId> connected) {
|
||||||
if (!running) return;
|
if (!running) return;
|
||||||
backoff.increment();
|
backoff.increment();
|
||||||
@@ -214,6 +227,7 @@ class BluetoothPlugin implements DuplexPlugin {
|
|||||||
final String uuid = e.getValue().get(PROP_UUID);
|
final String uuid = e.getValue().get(PROP_UUID);
|
||||||
if (StringUtils.isNullOrEmpty(uuid)) continue;
|
if (StringUtils.isNullOrEmpty(uuid)) continue;
|
||||||
ioExecutor.execute(new Runnable() {
|
ioExecutor.execute(new Runnable() {
|
||||||
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
if (!running) return;
|
if (!running) return;
|
||||||
StreamConnection s = connect(makeUrl(address, uuid));
|
StreamConnection s = connect(makeUrl(address, uuid));
|
||||||
@@ -238,6 +252,7 @@ class BluetoothPlugin implements DuplexPlugin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public DuplexTransportConnection createConnection(ContactId c) {
|
public DuplexTransportConnection createConnection(ContactId c) {
|
||||||
if (!running) return null;
|
if (!running) return null;
|
||||||
TransportProperties p = callback.getRemoteProperties().get(c);
|
TransportProperties p = callback.getRemoteProperties().get(c);
|
||||||
@@ -252,10 +267,12 @@ class BluetoothPlugin implements DuplexPlugin {
|
|||||||
return new BluetoothTransportConnection(this, s);
|
return new BluetoothTransportConnection(this, s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public boolean supportsInvitations() {
|
public boolean supportsInvitations() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public DuplexTransportConnection createInvitationConnection(PseudoRandom r,
|
public DuplexTransportConnection createInvitationConnection(PseudoRandom r,
|
||||||
long timeout, boolean alice) {
|
long timeout, boolean alice) {
|
||||||
if (!running) return null;
|
if (!running) return null;
|
||||||
@@ -279,9 +296,8 @@ class BluetoothPlugin implements DuplexPlugin {
|
|||||||
}
|
}
|
||||||
// Create the background tasks
|
// Create the background tasks
|
||||||
CompletionService<StreamConnection> complete =
|
CompletionService<StreamConnection> complete =
|
||||||
new ExecutorCompletionService<StreamConnection>(ioExecutor);
|
new ExecutorCompletionService<>(ioExecutor);
|
||||||
List<Future<StreamConnection>> futures =
|
List<Future<StreamConnection>> futures = new ArrayList<>();
|
||||||
new ArrayList<Future<StreamConnection>>();
|
|
||||||
if (alice) {
|
if (alice) {
|
||||||
// Return the first connected socket
|
// Return the first connected socket
|
||||||
futures.add(complete.submit(new ListeningTask(ss)));
|
futures.add(complete.submit(new ListeningTask(ss)));
|
||||||
@@ -316,6 +332,7 @@ class BluetoothPlugin implements DuplexPlugin {
|
|||||||
private void closeSockets(final List<Future<StreamConnection>> futures,
|
private void closeSockets(final List<Future<StreamConnection>> futures,
|
||||||
final StreamConnection chosen) {
|
final StreamConnection chosen) {
|
||||||
ioExecutor.execute(new Runnable() {
|
ioExecutor.execute(new Runnable() {
|
||||||
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
for (Future<StreamConnection> f : futures) {
|
for (Future<StreamConnection> f : futures) {
|
||||||
try {
|
try {
|
||||||
@@ -331,9 +348,7 @@ class BluetoothPlugin implements DuplexPlugin {
|
|||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
LOG.info("Interrupted while closing sockets");
|
LOG.info("Interrupted while closing sockets");
|
||||||
return;
|
return;
|
||||||
} catch (ExecutionException e) {
|
} catch (ExecutionException | IOException e) {
|
||||||
if (LOG.isLoggable(INFO)) LOG.info(e.toString());
|
|
||||||
} catch (IOException e) {
|
|
||||||
if (LOG.isLoggable(INFO)) LOG.info(e.toString());
|
if (LOG.isLoggable(INFO)) LOG.info(e.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -341,14 +356,15 @@ class BluetoothPlugin implements DuplexPlugin {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public boolean supportsKeyAgreement() {
|
public boolean supportsKeyAgreement() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public KeyAgreementListener createKeyAgreementListener(
|
@Override
|
||||||
byte[] localCommitment) {
|
public KeyAgreementListener createKeyAgreementListener(byte[] commitment) {
|
||||||
// No truncation necessary because COMMIT_LENGTH = 16
|
// No truncation necessary because COMMIT_LENGTH = 16
|
||||||
String uuid = UUID.nameUUIDFromBytes(localCommitment).toString();
|
String uuid = UUID.nameUUIDFromBytes(commitment).toString();
|
||||||
if (LOG.isLoggable(INFO)) LOG.info("Key agreement UUID " + uuid);
|
if (LOG.isLoggable(INFO)) LOG.info("Key agreement UUID " + uuid);
|
||||||
String url = makeUrl("localhost", uuid);
|
String url = makeUrl("localhost", uuid);
|
||||||
// Make the device discoverable if possible
|
// Make the device discoverable if possible
|
||||||
@@ -371,8 +387,9 @@ class BluetoothPlugin implements DuplexPlugin {
|
|||||||
return new BluetoothKeyAgreementListener(d, ss);
|
return new BluetoothKeyAgreementListener(d, ss);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public DuplexTransportConnection createKeyAgreementConnection(
|
public DuplexTransportConnection createKeyAgreementConnection(
|
||||||
byte[] remoteCommitment, TransportDescriptor d, long timeout) {
|
byte[] commitment, TransportDescriptor d, long timeout) {
|
||||||
if (!isRunning()) return null;
|
if (!isRunning()) return null;
|
||||||
if (!ID.equals(d.getIdentifier())) return null;
|
if (!ID.equals(d.getIdentifier())) return null;
|
||||||
TransportProperties p = d.getProperties();
|
TransportProperties p = d.getProperties();
|
||||||
@@ -380,7 +397,7 @@ class BluetoothPlugin implements DuplexPlugin {
|
|||||||
String address = p.get(PROP_ADDRESS);
|
String address = p.get(PROP_ADDRESS);
|
||||||
if (StringUtils.isNullOrEmpty(address)) return null;
|
if (StringUtils.isNullOrEmpty(address)) return null;
|
||||||
// No truncation necessary because COMMIT_LENGTH = 16
|
// No truncation necessary because COMMIT_LENGTH = 16
|
||||||
String uuid = UUID.nameUUIDFromBytes(remoteCommitment).toString();
|
String uuid = UUID.nameUUIDFromBytes(commitment).toString();
|
||||||
if (LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
LOG.info("Connecting to key agreement UUID " + uuid);
|
LOG.info("Connecting to key agreement UUID " + uuid);
|
||||||
String url = makeUrl(address, uuid);
|
String url = makeUrl(address, uuid);
|
||||||
|
|||||||
@@ -34,29 +34,36 @@ implements RemovableDriveMonitor.Callback {
|
|||||||
this.monitor = monitor;
|
this.monitor = monitor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public TransportId getId() {
|
public TransportId getId() {
|
||||||
return ID;
|
return ID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public boolean start() throws IOException {
|
public boolean start() throws IOException {
|
||||||
|
if (used.getAndSet(true)) throw new IllegalStateException();
|
||||||
running = true;
|
running = true;
|
||||||
monitor.start(this);
|
monitor.start(this);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void stop() throws IOException {
|
public void stop() throws IOException {
|
||||||
running = false;
|
running = false;
|
||||||
monitor.stop();
|
monitor.stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public boolean shouldPoll() {
|
public boolean shouldPoll() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public int getPollingInterval() {
|
public int getPollingInterval() {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void poll(Collection<ContactId> connected) {
|
public void poll(Collection<ContactId> connected) {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
@@ -64,8 +71,7 @@ implements RemovableDriveMonitor.Callback {
|
|||||||
@Override
|
@Override
|
||||||
protected File chooseOutputDirectory() {
|
protected File chooseOutputDirectory() {
|
||||||
try {
|
try {
|
||||||
List<File> drives =
|
List<File> drives = new ArrayList<>(finder.findRemovableDrives());
|
||||||
new ArrayList<File>(finder.findRemovableDrives());
|
|
||||||
if (drives.isEmpty()) return null;
|
if (drives.isEmpty()) return null;
|
||||||
String[] paths = new String[drives.size()];
|
String[] paths = new String[drives.size()];
|
||||||
for (int i = 0; i < paths.length; i++) {
|
for (int i = 0; i < paths.length; i++) {
|
||||||
@@ -92,7 +98,7 @@ implements RemovableDriveMonitor.Callback {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Collection<File> findFilesByName(String filename) {
|
protected Collection<File> findFilesByName(String filename) {
|
||||||
List<File> matches = new ArrayList<File>();
|
List<File> matches = new ArrayList<>();
|
||||||
try {
|
try {
|
||||||
for (File drive : finder.findRemovableDrives()) {
|
for (File drive : finder.findRemovableDrives()) {
|
||||||
File[] files = drive.listFiles();
|
File[] files = drive.listFiles();
|
||||||
@@ -109,6 +115,7 @@ implements RemovableDriveMonitor.Callback {
|
|||||||
return Collections.unmodifiableList(matches);
|
return Collections.unmodifiableList(matches);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void driveInserted(File root) {
|
public void driveInserted(File root) {
|
||||||
File[] files = root.listFiles();
|
File[] files = root.listFiles();
|
||||||
if (files != null) {
|
if (files != null) {
|
||||||
@@ -116,6 +123,7 @@ implements RemovableDriveMonitor.Callback {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void exceptionThrown(IOException e) {
|
public void exceptionThrown(IOException e) {
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import java.io.IOException;
|
|||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import static java.util.logging.Level.INFO;
|
import static java.util.logging.Level.INFO;
|
||||||
@@ -32,6 +33,7 @@ class ModemPlugin implements DuplexPlugin, Modem.Callback {
|
|||||||
private final SerialPortList serialPortList;
|
private final SerialPortList serialPortList;
|
||||||
private final DuplexPluginCallback callback;
|
private final DuplexPluginCallback callback;
|
||||||
private final int maxLatency;
|
private final int maxLatency;
|
||||||
|
private final AtomicBoolean used = new AtomicBoolean(false);
|
||||||
|
|
||||||
private volatile boolean running = false;
|
private volatile boolean running = false;
|
||||||
private volatile Modem modem = null;
|
private volatile Modem modem = null;
|
||||||
@@ -44,20 +46,25 @@ class ModemPlugin implements DuplexPlugin, Modem.Callback {
|
|||||||
this.maxLatency = maxLatency;
|
this.maxLatency = maxLatency;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public TransportId getId() {
|
public TransportId getId() {
|
||||||
return ID;
|
return ID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public int getMaxLatency() {
|
public int getMaxLatency() {
|
||||||
return maxLatency;
|
return maxLatency;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public int getMaxIdleTime() {
|
public int getMaxIdleTime() {
|
||||||
// FIXME: Do we need keepalives for this transport?
|
// FIXME: Do we need keepalives for this transport?
|
||||||
return Integer.MAX_VALUE;
|
return Integer.MAX_VALUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public boolean start() {
|
public boolean start() {
|
||||||
|
if (used.getAndSet(true)) throw new IllegalStateException();
|
||||||
for (String portName : serialPortList.getPortNames()) {
|
for (String portName : serialPortList.getPortNames()) {
|
||||||
if (LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
LOG.info("Trying to initialise modem on " + portName);
|
LOG.info("Trying to initialise modem on " + portName);
|
||||||
@@ -75,6 +82,7 @@ class ModemPlugin implements DuplexPlugin, Modem.Callback {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void stop() {
|
public void stop() {
|
||||||
running = false;
|
running = false;
|
||||||
if (modem != null) {
|
if (modem != null) {
|
||||||
@@ -86,18 +94,22 @@ class ModemPlugin implements DuplexPlugin, Modem.Callback {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public boolean isRunning() {
|
public boolean isRunning() {
|
||||||
return running;
|
return running;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public boolean shouldPoll() {
|
public boolean shouldPoll() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public int getPollingInterval() {
|
public int getPollingInterval() {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void poll(Collection<ContactId> connected) {
|
public void poll(Collection<ContactId> connected) {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
@@ -121,6 +133,7 @@ class ModemPlugin implements DuplexPlugin, Modem.Callback {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public DuplexTransportConnection createConnection(ContactId c) {
|
public DuplexTransportConnection createConnection(ContactId c) {
|
||||||
if (!running) return null;
|
if (!running) return null;
|
||||||
// Get the ISO 3166 code for the caller's country
|
// Get the ISO 3166 code for the caller's country
|
||||||
@@ -148,29 +161,34 @@ class ModemPlugin implements DuplexPlugin, Modem.Callback {
|
|||||||
return new ModemTransportConnection();
|
return new ModemTransportConnection();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public boolean supportsInvitations() {
|
public boolean supportsInvitations() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public DuplexTransportConnection createInvitationConnection(PseudoRandom r,
|
public DuplexTransportConnection createInvitationConnection(PseudoRandom r,
|
||||||
long timeout, boolean alice) {
|
long timeout, boolean alice) {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public boolean supportsKeyAgreement() {
|
public boolean supportsKeyAgreement() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public KeyAgreementListener createKeyAgreementListener(
|
@Override
|
||||||
byte[] commitment) {
|
public KeyAgreementListener createKeyAgreementListener(byte[] commitment) {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public DuplexTransportConnection createKeyAgreementConnection(
|
public DuplexTransportConnection createKeyAgreementConnection(
|
||||||
byte[] commitment, TransportDescriptor d, long timeout) {
|
byte[] commitment, TransportDescriptor d, long timeout) {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void incomingCallConnected() {
|
public void incomingCallConnected() {
|
||||||
LOG.info("Incoming call connected");
|
LOG.info("Incoming call connected");
|
||||||
callback.incomingConnectionCreated(new ModemTransportConnection());
|
callback.incomingConnectionCreated(new ModemTransportConnection());
|
||||||
|
|||||||
Reference in New Issue
Block a user