Invitation API and two (untested) implementations.

This commit is contained in:
akwizgran
2011-10-27 17:52:03 +01:00
parent 59485fe392
commit 48d638746c
26 changed files with 834 additions and 251 deletions

View File

@@ -23,4 +23,28 @@ public interface BatchPlugin extends Plugin {
* Returns null if a writer could not be created.
*/
BatchTransportWriter createWriter(ContactId c);
/**
* Starts the invitation process from the inviter's side. Returns null if
* no connection can be established within the given timeout.
*/
BatchTransportWriter sendInvitation(int code, long timeout);
/**
* Starts the invitation process from the invitee's side. Returns null if
* no connection can be established within the given timeout.
*/
BatchTransportReader acceptInvitation(int code, long timeout);
/**
* Continues the invitation process from the invitee's side. Returns null
* if no connection can be established within the given timeout.
*/
BatchTransportWriter sendInvitationResponse(int code, long timeout);
/**
* Continues the invitation process from the inviter's side. Returns null
* if no connection can be established within the given timeout.
*/
BatchTransportReader acceptInvitationResponse(int code, long timeout);
}

View File

@@ -15,4 +15,16 @@ public interface StreamPlugin extends Plugin {
* Returns null if a connection could not be created.
*/
StreamTransportConnection createConnection(ContactId c);
/**
* Starts the invitation process from the inviter's side. Returns null if
* no connection can be established within the given timeout.
*/
StreamTransportConnection sendInvitation(int code, long timeout);
/**
* Starts the invitation process from the invitee's side. Returns null if
* no connection can be established within the given timeout.
*/
StreamTransportConnection acceptInvitation(int code, long timeout);
}

View File

@@ -36,7 +36,10 @@ class DatabaseCleanerImpl implements DatabaseCleaner, Runnable {
} else {
try {
wait(msBetweenSweeps);
} catch(InterruptedException ignored) {}
} catch(InterruptedException e) {
if(LOG.isLoggable(Level.WARNING))
LOG.warning(e.getMessage());
}
}
} catch(DbException e) {
if(LOG.isLoggable(Level.WARNING))

View File

@@ -362,7 +362,10 @@ abstract class JdbcDatabase implements Database<Connection> {
while(closed) {
try {
connections.wait();
} catch(InterruptedException ignored) {}
} catch(InterruptedException e) {
if(LOG.isLoggable(Level.WARNING))
LOG.warning(e.getMessage());
}
}
txn = connections.poll();
}
@@ -433,7 +436,10 @@ abstract class JdbcDatabase implements Database<Connection> {
+ " open connections");
try {
connections.wait();
} catch(InterruptedException ignored) {}
} catch(InterruptedException e) {
if(LOG.isLoggable(Level.WARNING))
LOG.warning(e.getMessage());
}
for(Connection c : connections) c.close();
openConnections -= connections.size();
connections.clear();

View File

@@ -12,15 +12,17 @@ import java.util.MissingResourceException;
import java.util.ResourceBundle;
import java.util.Scanner;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.UIManager;
import com.google.inject.Inject;
import net.sf.briar.api.i18n.FontManager;
import net.sf.briar.api.i18n.I18n;
import net.sf.briar.util.FileUtils;
import com.google.inject.Inject;
// Needs to be public for installer
public class I18nImpl implements I18n {
@@ -70,6 +72,9 @@ public class I18nImpl implements I18n {
"ProgressMonitor.progressText"
};
private static final Logger LOG =
Logger.getLogger(I18nImpl.class.getName());
private final Object bundleLock = new Object();
private final ClassLoader loader = I18n.class.getClassLoader();
private final Set<Listener> listeners = new HashSet<Listener>();
@@ -97,7 +102,10 @@ public class I18nImpl implements I18n {
for(String key : uiManagerKeys) {
try {
UIManager.put(key, bundle.getString(key));
} catch(MissingResourceException ignored) {}
} catch(MissingResourceException e) {
if(LOG.isLoggable(Level.WARNING))
LOG.warning(e.getMessage());
}
}
}
}

View File

@@ -9,8 +9,7 @@ public abstract class AbstractPlugin implements Plugin {
protected final Executor executor;
// This field must only be accessed with this's lock held
protected boolean started = false;
protected boolean started = false; // Locking: this
protected AbstractPlugin(Executor executor) {
this.executor = executor;

View File

@@ -51,7 +51,10 @@ class PollerImpl implements Poller, Runnable {
} else {
try {
wait(p.time - now);
} catch(InterruptedException ignored) {}
} catch(InterruptedException e) {
if(LOG.isLoggable(Level.WARNING))
LOG.warning(e.getMessage());
}
}
}
}

View File

@@ -21,8 +21,8 @@ import net.sf.briar.api.ContactId;
import net.sf.briar.api.TransportConfig;
import net.sf.briar.api.TransportId;
import net.sf.briar.api.TransportProperties;
import net.sf.briar.api.plugins.StreamPluginCallback;
import net.sf.briar.api.plugins.StreamPlugin;
import net.sf.briar.api.plugins.StreamPluginCallback;
import net.sf.briar.api.transport.StreamTransportConnection;
import net.sf.briar.plugins.AbstractPlugin;
import net.sf.briar.util.OsUtils;
@@ -36,11 +36,12 @@ class BluetoothPlugin extends AbstractPlugin implements StreamPlugin {
private static final Logger LOG =
Logger.getLogger(BluetoothPlugin.class.getName());
private final Object discoveryLock = new Object();
private final StreamPluginCallback callback;
private final long pollingInterval;
private LocalDevice localDevice = null;
private StreamConnectionNotifier streamConnectionNotifier = null;
private LocalDevice localDevice = null; // Locking: this
private StreamConnectionNotifier socket = null; // Locking: this
BluetoothPlugin(Executor executor, StreamPluginCallback callback,
long pollingInterval) {
@@ -72,40 +73,35 @@ class BluetoothPlugin extends AbstractPlugin implements StreamPlugin {
}
throw new IOException(e.getMessage());
}
executor.execute(createBinder());
executor.execute(createContactSocketBinder());
}
@Override
public synchronized void stop() throws IOException {
super.stop();
if(streamConnectionNotifier != null) {
streamConnectionNotifier.close();
streamConnectionNotifier = null;
if(socket != null) {
socket.close();
socket = null;
}
}
private Runnable createBinder() {
private Runnable createContactSocketBinder() {
return new Runnable() {
public void run() {
bind();
bindContactSocket();
}
};
}
private void bind() {
private void bindContactSocket() {
String uuid;
synchronized(this) {
if(!started) return;
uuid = getUuid();
makeDeviceDiscoverable();
}
// Try to make the device discoverable (requires root on Linux)
try {
localDevice.setDiscoverable(DiscoveryAgent.GIAC);
} catch(BluetoothStateException e) {
if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.getMessage());
}
// Bind the port
String url = "btspp://localhost:" + uuid + ";name=" + uuid;
// Bind the socket
String url = "btspp://localhost:" + uuid + ";name=RFCOMM";
StreamConnectionNotifier scn;
try {
scn = (StreamConnectionNotifier) Connector.open(url);
@@ -123,10 +119,10 @@ class BluetoothPlugin extends AbstractPlugin implements StreamPlugin {
}
return;
}
streamConnectionNotifier = scn;
socket = scn;
setLocalBluetoothAddress(localDevice.getBluetoothAddress());
}
startListener();
startContactAccepterThread();
}
private synchronized String getUuid() {
@@ -144,32 +140,13 @@ class BluetoothPlugin extends AbstractPlugin implements StreamPlugin {
return uuid;
}
private void startListener() {
new Thread() {
@Override
public void run() {
listen();
}
}.start();
}
private void listen() {
while(true) {
StreamConnectionNotifier scn;
StreamConnection s;
synchronized(this) {
if(!started) return;
scn = streamConnectionNotifier;
}
try {
s = scn.acceptAndOpen();
} catch(IOException e) {
if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.getMessage());
return;
}
BluetoothTransportConnection conn =
new BluetoothTransportConnection(s);
callback.incomingConnectionCreated(conn);
private synchronized void makeDeviceDiscoverable() {
assert started;
// Try to make the device discoverable (requires root on Linux)
try {
localDevice.setDiscoverable(DiscoveryAgent.GIAC);
} catch(BluetoothStateException e) {
if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.getMessage());
}
}
@@ -180,6 +157,35 @@ class BluetoothPlugin extends AbstractPlugin implements StreamPlugin {
callback.setLocalProperties(p);
}
private void startContactAccepterThread() {
new Thread() {
@Override
public void run() {
acceptContactConnections();
}
}.start();
}
private void acceptContactConnections() {
while(true) {
StreamConnectionNotifier scn;
StreamConnection s;
synchronized(this) {
if(!started) return;
scn = socket;
}
try {
s = scn.acceptAndOpen();
} catch(IOException e) {
// This is expected when the socket is closed
if(LOG.isLoggable(Level.INFO)) LOG.info(e.getMessage());
return;
}
callback.incomingConnectionCreated(
new BluetoothTransportConnection(s));
}
}
public boolean shouldPoll() {
return true;
}
@@ -202,58 +208,53 @@ class BluetoothPlugin extends AbstractPlugin implements StreamPlugin {
}
private void connectAndCallBack() {
Map<ContactId, String> discovered = discover();
Map<ContactId, String> discovered = discoverContactUrls();
for(Entry<ContactId, String> e : discovered.entrySet()) {
ContactId c = e.getKey();
String url = e.getValue();
StreamTransportConnection conn = connect(c, url);
if(conn != null) callback.outgoingConnectionCreated(c, conn);
StreamTransportConnection s = connect(c, url);
if(s != null) callback.outgoingConnectionCreated(c, s);
}
}
private Map<ContactId, String> discover() {
private Map<ContactId, String> discoverContactUrls() {
DiscoveryAgent discoveryAgent;
Map<String, ContactId> addresses;
Map<ContactId, String> uuids;
Map<ContactId, TransportProperties> remote;
synchronized(this) {
if(!started) return Collections.emptyMap();
discoveryAgent = localDevice.getDiscoveryAgent();
addresses = new HashMap<String, ContactId>();
uuids = new HashMap<ContactId, String>();
Map<ContactId, TransportProperties> remote =
callback.getRemoteProperties();
for(Entry<ContactId, TransportProperties> e : remote.entrySet()) {
ContactId c = e.getKey();
TransportProperties p = e.getValue();
String address = p.get("address");
String uuid = p.get("uuid");
if(address != null && uuid != null) {
addresses.put(address, c);
uuids.put(c, uuid);
}
remote = callback.getRemoteProperties();
}
Map<String, ContactId> addresses = new HashMap<String, ContactId>();
Map<ContactId, String> uuids = new HashMap<ContactId, String>();
for(Entry<ContactId, TransportProperties> e : remote.entrySet()) {
ContactId c = e.getKey();
TransportProperties p = e.getValue();
String address = p.get("address");
String uuid = p.get("uuid");
if(address != null && uuid != null) {
addresses.put(address, c);
uuids.put(c, uuid);
}
}
BluetoothListener listener =
new BluetoothListener(discoveryAgent, addresses, uuids);
try {
synchronized(listener) {
ContactListener listener = new ContactListener(discoveryAgent,
addresses, uuids);
synchronized(discoveryLock) {
try {
discoveryAgent.startInquiry(DiscoveryAgent.GIAC, listener);
listener.wait();
return listener.waitForUrls();
} catch(BluetoothStateException e) {
if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.getMessage());
return Collections.emptyMap();
}
} catch(BluetoothStateException e) {
if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.getMessage());
} catch(InterruptedException ignored) {}
return listener.getUrls();
}
}
private StreamTransportConnection connect(ContactId c, String url) {
synchronized(this) {
if(!started) return null;
}
try {
synchronized(this) {
if(!started) return null;
Map<ContactId, TransportProperties> remote =
callback.getRemoteProperties();
if(!remote.containsKey(c)) return null;
}
StreamConnection s = (StreamConnection) Connector.open(url);
return new BluetoothTransportConnection(s);
} catch(IOException e) {
@@ -263,8 +264,137 @@ class BluetoothPlugin extends AbstractPlugin implements StreamPlugin {
}
public StreamTransportConnection createConnection(ContactId c) {
Map<ContactId, String> discovered = discover();
String url = discovered.get(c);
String url = discoverContactUrls().get(c);
return url == null ? null : connect(c, url);
}
public StreamTransportConnection sendInvitation(int code, long timeout) {
return createInvitationConnection(code, timeout);
}
public StreamTransportConnection acceptInvitation(int code, long timeout) {
return createInvitationConnection(code, timeout);
}
private StreamTransportConnection createInvitationConnection(int code,
long timeout) {
// The invitee's device may not be discoverable, so both parties must
// try to initiate connections
String uuid = convertInvitationCodeToUuid(code);
ConnectionCallback c = new ConnectionCallback(uuid, timeout);
startOutgoingInvitationThread(c);
startIncomingInvitationThread(c);
StreamConnection s = c.waitForConnection();
return s == null ? null : new BluetoothTransportConnection(s);
}
private String convertInvitationCodeToUuid(int code) {
byte[] b = new byte[16];
new Random(code).nextBytes(b);
return StringUtils.toHexString(b);
}
private void startOutgoingInvitationThread(final ConnectionCallback c) {
new Thread() {
@Override
public void run() {
createInvitationConnection(c);
}
}.start();
}
private void createInvitationConnection(ConnectionCallback c) {
DiscoveryAgent discoveryAgent;
synchronized(this) {
if(!started) return;
discoveryAgent = localDevice.getDiscoveryAgent();
}
// Try to discover the other party until the invitation times out
long end = System.currentTimeMillis() + c.getTimeout();
String url = null;
while(url == null && System.currentTimeMillis() < end) {
InvitationListener listener = new InvitationListener(discoveryAgent,
c.getUuid());
synchronized(discoveryLock) {
try {
discoveryAgent.startInquiry(DiscoveryAgent.GIAC, listener);
url = listener.waitForUrl();
} catch(BluetoothStateException e) {
if(LOG.isLoggable(Level.WARNING))
LOG.warning(e.getMessage());
return;
}
}
synchronized(this) {
if(!started) return;
}
}
if(url == null) return;
// Try to connect to the other party
try {
StreamConnection s = (StreamConnection) Connector.open(url);
c.addConnection(s);
} catch(IOException e) {
if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.getMessage());
}
}
private void startIncomingInvitationThread(final ConnectionCallback c) {
new Thread() {
@Override
public void run() {
bindInvitationSocket(c);
}
}.start();
}
private void bindInvitationSocket(ConnectionCallback c) {
synchronized(this) {
if(!started) return;
makeDeviceDiscoverable();
}
// Bind the socket
String url = "btspp://localhost:" + c.getUuid() + ";name=RFCOMM";
StreamConnectionNotifier scn;
try {
scn = (StreamConnectionNotifier) Connector.open(url);
} catch(IOException e) {
if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.getMessage());
return;
}
startInvitationAccepterThread(c, scn);
// Close the socket when the invitation times out
try {
Thread.sleep(c.getTimeout());
scn.close();
} catch(InterruptedException e) {
if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.getMessage());
} catch(IOException e) {
if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.getMessage());
}
}
private void startInvitationAccepterThread(final ConnectionCallback c,
final StreamConnectionNotifier scn) {
new Thread() {
@Override
public void run() {
acceptInvitationConnection(c, scn);
}
}.start();
}
private void acceptInvitationConnection(ConnectionCallback c,
StreamConnectionNotifier scn) {
synchronized(this) {
if(!started) return;
}
try {
StreamConnection s = scn.acceptAndOpen();
c.addConnection(s);
} catch(IOException e) {
// This is expected when the socket is closed
if(LOG.isLoggable(Level.INFO)) LOG.info(e.getMessage());
}
}
}

View File

@@ -0,0 +1,60 @@
package net.sf.briar.plugins.bluetooth;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.microedition.io.StreamConnection;
class ConnectionCallback {
private static final Logger LOG =
Logger.getLogger(ConnectionCallback.class.getName());
private final String uuid;
private final long timeout;
private final long end;
private StreamConnection connection = null; // Locking: this
ConnectionCallback(String uuid, long timeout) {
this.uuid = uuid;
this.timeout = timeout;
end = System.currentTimeMillis() + timeout;
}
String getUuid() {
return uuid;
}
long getTimeout() {
return timeout;
}
synchronized StreamConnection waitForConnection() {
long now = System.currentTimeMillis();
while(connection == null && now < end) {
try {
wait(end - now);
} catch(InterruptedException e) {
if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.getMessage());
}
now = System.currentTimeMillis();
}
return connection;
}
synchronized void addConnection(StreamConnection s) {
if(connection == null) {
connection = s;
notifyAll();
} else {
// Redundant connection
try {
s.close();
} catch(IOException e) {
if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.getMessage());
}
}
}
}

View File

@@ -1,6 +1,7 @@
package net.sf.briar.plugins.bluetooth;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
@@ -8,6 +9,7 @@ import java.util.logging.Level;
import java.util.logging.Logger;
import javax.bluetooth.BluetoothStateException;
import javax.bluetooth.DataElement;
import javax.bluetooth.DeviceClass;
import javax.bluetooth.DiscoveryAgent;
import javax.bluetooth.DiscoveryListener;
@@ -17,12 +19,10 @@ import javax.bluetooth.UUID;
import net.sf.briar.api.ContactId;
class BluetoothListener implements DiscoveryListener {
class ContactListener implements DiscoveryListener {
private static final Logger LOG =
Logger.getLogger(BluetoothListener.class.getName());
private static final int[] ATTRIBUTES = { 0x100 }; // Service name
Logger.getLogger(ContactListener.class.getName());
private final AtomicInteger searches = new AtomicInteger(1);
private final DiscoveryAgent discoveryAgent;
@@ -30,7 +30,9 @@ class BluetoothListener implements DiscoveryListener {
private final Map<ContactId, String> uuids;
private final Map<ContactId, String> urls;
BluetoothListener(DiscoveryAgent discoveryAgent,
private boolean finished = false; // Locking: this
ContactListener(DiscoveryAgent discoveryAgent,
Map<String, ContactId> addresses, Map<ContactId, String> uuids) {
this.discoveryAgent = discoveryAgent;
this.addresses = addresses;
@@ -38,7 +40,14 @@ class BluetoothListener implements DiscoveryListener {
urls = Collections.synchronizedMap(new HashMap<ContactId, String>());
}
public Map<ContactId, String> getUrls() {
public synchronized Map<ContactId, String> waitForUrls() {
while(!finished) {
try {
wait();
} catch(InterruptedException e) {
if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.getMessage());
}
}
return urls;
}
@@ -52,7 +61,7 @@ class BluetoothListener implements DiscoveryListener {
UUID[] uuids = new UUID[] { new UUID(uuid, false) };
// Try to discover the services associated with the UUID
try {
discoveryAgent.searchServices(ATTRIBUTES, uuids, device, this);
discoveryAgent.searchServices(null, uuids, device, this);
} catch(BluetoothStateException e) {
if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.getMessage());
}
@@ -62,6 +71,7 @@ class BluetoothListener implements DiscoveryListener {
public void inquiryCompleted(int discoveryType) {
if(searches.decrementAndGet() == 0) {
synchronized(this) {
finished = true;
notifyAll();
}
}
@@ -73,16 +83,33 @@ class BluetoothListener implements DiscoveryListener {
RemoteDevice device = record.getHostDevice();
ContactId c = addresses.get(device.getBluetoothAddress());
if(c == null) continue;
// Store the URL
String url = record.getConnectionURL(
// Do we have a UUID for this contact?
String uuid = uuids.get(c);
if(uuid == null) return;
// Does this service have a URL?
String serviceUrl = record.getConnectionURL(
ServiceRecord.NOAUTHENTICATE_NOENCRYPT, false);
if(url != null) urls.put(c, url);
if(serviceUrl == null) continue;
// Does this service have the UUID we're looking for?
DataElement classIds = record.getAttributeValue(0x1);
if(classIds == null) continue;
@SuppressWarnings("unchecked")
Enumeration<DataElement> e =
(Enumeration<DataElement>) classIds.getValue();
for(DataElement classId : Collections.list(e)) {
UUID serviceUuid = (UUID) classId.getValue();
if(uuid.equals(serviceUuid.toString())) {
// The UUID matches - store the URL
urls.put(c, serviceUrl);
}
}
}
}
public void serviceSearchCompleted(int transaction, int response) {
if(searches.decrementAndGet() == 0) {
synchronized(this) {
finished = true;
notifyAll();
}
}

View File

@@ -0,0 +1,101 @@
package net.sf.briar.plugins.bluetooth;
import java.util.Collections;
import java.util.Enumeration;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.bluetooth.BluetoothStateException;
import javax.bluetooth.DataElement;
import javax.bluetooth.DeviceClass;
import javax.bluetooth.DiscoveryAgent;
import javax.bluetooth.DiscoveryListener;
import javax.bluetooth.RemoteDevice;
import javax.bluetooth.ServiceRecord;
import javax.bluetooth.UUID;
class InvitationListener implements DiscoveryListener {
private static final Logger LOG =
Logger.getLogger(InvitationListener.class.getName());
private final AtomicInteger searches = new AtomicInteger(1);
private final DiscoveryAgent discoveryAgent;
private final String uuid;
private String url = null; // Locking: this
private boolean finished = false; // Locking: this
InvitationListener(DiscoveryAgent discoveryAgent, String uuid) {
this.discoveryAgent = discoveryAgent;
this.uuid = uuid;
}
synchronized String waitForUrl() {
while(!finished) {
try {
wait();
} catch(InterruptedException e) {
if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.getMessage());
}
}
return url;
}
public void deviceDiscovered(RemoteDevice device, DeviceClass deviceClass) {
UUID[] uuids = new UUID[] { new UUID(uuid, false) };
// Try to discover the services associated with the UUID
try {
discoveryAgent.searchServices(null, uuids, device, this);
searches.incrementAndGet();
} catch(BluetoothStateException e) {
if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.getMessage());
}
}
public void inquiryCompleted(int discoveryType) {
if(searches.decrementAndGet() == 0) {
synchronized(this) {
finished = true;
notifyAll();
}
}
}
public void servicesDiscovered(int transaction, ServiceRecord[] services) {
for(ServiceRecord record : services) {
// Does this service have a URL?
String serviceUrl = record.getConnectionURL(
ServiceRecord.NOAUTHENTICATE_NOENCRYPT, false);
if(serviceUrl == null) continue;
// Does this service have the UUID we're looking for?
DataElement classIds = record.getAttributeValue(0x1);
if(classIds == null) continue;
@SuppressWarnings("unchecked")
Enumeration<DataElement> e =
(Enumeration<DataElement>) classIds.getValue();
for(DataElement classId : Collections.list(e)) {
UUID serviceUuid = (UUID) classId.getValue();
if(uuid.equals(serviceUuid.toString())) {
// The UUID matches - store the URL
synchronized(this) {
url = serviceUrl;
finished = true;
notifyAll();
}
return;
}
}
}
}
public void serviceSearchCompleted(int transaction, int response) {
if(searches.decrementAndGet() == 0) {
synchronized(this) {
finished = true;
notifyAll();
}
}
}
}

View File

@@ -0,0 +1,41 @@
package net.sf.briar.plugins.file;
import java.io.File;
import java.util.logging.Level;
import java.util.logging.Logger;
class FileListener {
private static final Logger LOG =
Logger.getLogger(FileListener.class.getName());
private final String filename;
private final long end;
private File file = null; // Locking: this
FileListener(String filename, long timeout) {
this.filename = filename;
end = System.currentTimeMillis() + timeout;
}
synchronized File waitForFile() {
long now = System.currentTimeMillis();
while(file == null && now < end) {
try {
wait(end - now);
} catch(InterruptedException e) {
if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.getMessage());
}
now = System.currentTimeMillis();
}
return file;
}
synchronized void addFile(File f) {
if(filename.equals(f.getName())) {
file = f;
notifyAll();
}
}
}

View File

@@ -5,13 +5,14 @@ import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Collection;
import java.util.concurrent.Executor;
import java.util.logging.Level;
import java.util.logging.Logger;
import net.sf.briar.api.ContactId;
import net.sf.briar.api.plugins.BatchPluginCallback;
import net.sf.briar.api.plugins.BatchPlugin;
import net.sf.briar.api.plugins.BatchPluginCallback;
import net.sf.briar.api.transport.BatchTransportReader;
import net.sf.briar.api.transport.BatchTransportWriter;
import net.sf.briar.api.transport.TransportConstants;
@@ -26,7 +27,11 @@ abstract class FilePlugin extends AbstractPlugin implements BatchPlugin {
protected final BatchPluginCallback callback;
private final Object listenerLock = new Object();
private FileListener listener = null; // Locking: listenerLock
protected abstract File chooseOutputDirectory();
protected abstract Collection<File> findFilesByName(String filename);
protected abstract void writerFinished(File f);
protected abstract void readerFinished(File f);
@@ -40,12 +45,28 @@ abstract class FilePlugin extends AbstractPlugin implements BatchPlugin {
}
public BatchTransportWriter createWriter(ContactId c) {
return createWriter(createConnectionFilename());
}
private String createConnectionFilename() {
StringBuilder s = new StringBuilder(12);
for(int i = 0; i < 8; i++) s.append((char) ('a' + Math.random() * 26));
s.append(".dat");
return s.toString();
}
// Package access for testing
boolean isPossibleConnectionFilename(String filename) {
return filename.toLowerCase().matches("[a-z]{8}\\.dat");
}
private BatchTransportWriter createWriter(String filename) {
synchronized(this) {
if(!started) return null;
}
File dir = chooseOutputDirectory();
if(dir == null || !dir.exists() || !dir.isDirectory()) return null;
File f = new File(dir, createFilename());
File f = new File(dir, filename);
try {
long capacity = getCapacity(dir.getPath());
if(capacity < TransportConstants.MIN_CONNECTION_LENGTH) return null;
@@ -58,13 +79,6 @@ abstract class FilePlugin extends AbstractPlugin implements BatchPlugin {
}
}
private String createFilename() {
StringBuilder s = new StringBuilder(12);
for(int i = 0; i < 8; i++) s.append((char) ('a' + Math.random() * 26));
s.append(".dat");
return s.toString();
}
private long getCapacity(String path) throws IOException {
return FileSystemUtils.freeSpaceKb(path) * 1024L;
}
@@ -74,9 +88,60 @@ abstract class FilePlugin extends AbstractPlugin implements BatchPlugin {
executor.execute(new ReaderCreator(f));
}
public BatchTransportWriter sendInvitation(int code, long timeout) {
return createWriter(createInvitationFilename(code, false));
}
public BatchTransportReader acceptInvitation(int code, long timeout) {
String filename = createInvitationFilename(code, false);
return createInvitationReader(filename, timeout);
}
public BatchTransportWriter sendInvitationResponse(int code, long timeout) {
return createWriter(createInvitationFilename(code, true));
}
public BatchTransportReader acceptInvitationResponse(int code,
long timeout) {
String filename = createInvitationFilename(code, true);
return createInvitationReader(filename, timeout);
}
private BatchTransportReader createInvitationReader(String filename,
long timeout) {
Collection<File> files;
synchronized(listenerLock) {
// Find any matching files that have already arrived
files = findFilesByName(filename);
if(files.isEmpty()) {
// Wait for a matching file to arrive
listener = new FileListener(filename, timeout);
File f = listener.waitForFile();
if(f != null) files.add(f);
listener = null;
}
}
// Return the first match that can be opened
for(File f : files) {
try {
FileInputStream in = new FileInputStream(f);
return new FileTransportReader(f, in, FilePlugin.this);
} catch(IOException e) {
if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.getMessage());
}
}
return null;
}
private String createInvitationFilename(int code, boolean response) {
assert code >= 0;
assert code < 10 * 1000 * 1000;
return String.format("%c%7d.dat", response ? 'b' : 'a', code);
}
// Package access for testing
boolean isPossibleConnectionFilename(String filename) {
return filename.toLowerCase().matches("[a-z]{8}\\.dat");
boolean isPossibleInvitationFilename(String filename) {
return filename.toLowerCase().matches("[ab][0-9]{7}.dat");
}
private class ReaderCreator implements Runnable {
@@ -88,14 +153,21 @@ abstract class FilePlugin extends AbstractPlugin implements BatchPlugin {
}
public void run() {
if(!isPossibleConnectionFilename(f.getName())) return;
if(f.length() < TransportConstants.MIN_CONNECTION_LENGTH) return;
try {
FileInputStream in = new FileInputStream(f);
callback.readerCreated(new FileTransportReader(f, in,
FilePlugin.this));
} catch(IOException e) {
if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.getMessage());
String filename = f.getName();
if(isPossibleInvitationFilename(filename)) {
synchronized(listenerLock) {
if(listener != null) listener.addFile(f);
}
}
if(isPossibleConnectionFilename(f.getName())) {
try {
FileInputStream in = new FileInputStream(f);
callback.readerCreated(new FileTransportReader(f, in,
FilePlugin.this));
} catch(IOException e) {
if(LOG.isLoggable(Level.WARNING))
LOG.warning(e.getMessage());
}
}
}
}

View File

@@ -3,9 +3,14 @@ package net.sf.briar.plugins.file;
import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
class PollingRemovableDriveMonitor implements RemovableDriveMonitor, Runnable {
private static final Logger LOG =
Logger.getLogger(PollingRemovableDriveMonitor.class.getName());
private final RemovableDriveFinder finder;
private final long pollingInterval;
private final Object pollingLock = new Object();
@@ -47,7 +52,10 @@ class PollingRemovableDriveMonitor implements RemovableDriveMonitor, Runnable {
synchronized(pollingLock) {
try {
pollingLock.wait(pollingInterval);
} catch(InterruptedException ignored) {}
} catch(InterruptedException e) {
if(LOG.isLoggable(Level.WARNING))
LOG.warning(e.getMessage());
}
}
if(!running) return;
List<File> newDrives = finder.findRemovableDrives();

View File

@@ -2,6 +2,8 @@ package net.sf.briar.plugins.file;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.Executor;
import java.util.logging.Level;
@@ -85,8 +87,29 @@ implements RemovableDriveMonitor.Callback {
callback.showMessage("REMOVABLE_DRIVE_WRITE_FINISHED");
}
@Override
protected Collection<File> findFilesByName(String filename) {
Collection<File> matches = new ArrayList<File>();
try {
for(File drive : finder.findRemovableDrives()) {
File[] files = drive.listFiles();
if(files != null) {
for(File f : files) {
if(f.isFile() && filename.equals(f.getName()))
matches.add(f);
}
}
}
} catch(IOException e) {
if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.getMessage());
}
return matches;
}
public void driveInserted(File root) {
File[] files = root.listFiles();
if(files != null) for(File f : files) createReaderFromFile(f);
if(files != null) {
for(File f : files) if(f.isFile()) createReaderFromFile(f);
}
}
}

View File

@@ -1,6 +1,7 @@
package net.sf.briar.plugins.socket;
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
@@ -11,6 +12,7 @@ import net.sf.briar.api.ContactId;
import net.sf.briar.api.TransportId;
import net.sf.briar.api.TransportProperties;
import net.sf.briar.api.plugins.StreamPluginCallback;
import net.sf.briar.api.transport.StreamTransportConnection;
class SimpleSocketPlugin extends SocketPlugin {
@@ -67,7 +69,8 @@ class SimpleSocketPlugin extends SocketPlugin {
TransportProperties p) {
assert started;
assert p != null;
String host = p.get("host");
String host = p.get("external");
if(host == null) host = p.get("internal");
String portString = p.get("port");
if(host == null || portString == null) return null;
int port;
@@ -85,12 +88,22 @@ class SimpleSocketPlugin extends SocketPlugin {
if(!(s instanceof InetSocketAddress))
throw new IllegalArgumentException();
InetSocketAddress i = (InetSocketAddress) s;
String host = i.getAddress().getHostAddress();
String port = String.valueOf(i.getPort());
// FIXME: Special handling for private IP addresses?
InetAddress addr = i.getAddress();
TransportProperties p = callback.getLocalProperties();
p.put("host", host);
p.put("port", port);
if(addr.isLinkLocalAddress() || addr.isSiteLocalAddress())
p.put("internal", addr.getHostAddress());
else p.put("external", addr.getHostAddress());
p.put("port", String.valueOf(i.getPort()));
callback.setLocalProperties(p);
}
public StreamTransportConnection sendInvitation(int code, long timeout) {
// FIXME
return null;
}
public StreamTransportConnection acceptInvitation(int code, long timeout) {
// FIXME
return null;
}
}

View File

@@ -21,8 +21,7 @@ abstract class SocketPlugin extends AbstractPlugin implements StreamPlugin {
protected final StreamPluginCallback callback;
// This field must only be accessed with this's lock held
protected ServerSocket socket = null;
protected ServerSocket socket = null; // Locking: this
protected abstract void setLocalSocketAddress(SocketAddress s);
@@ -85,10 +84,10 @@ abstract class SocketPlugin extends AbstractPlugin implements StreamPlugin {
socket = ss;
setLocalSocketAddress(ss.getLocalSocketAddress());
}
startListener();
startListenerThread();
}
private void startListener() {
private void startListenerThread() {
new Thread() {
@Override
public void run() {
@@ -108,7 +107,8 @@ abstract class SocketPlugin extends AbstractPlugin implements StreamPlugin {
try {
s = ss.accept();
} catch(IOException e) {
if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.getMessage());
// This is expected when the socket is closed
if(LOG.isLoggable(Level.INFO)) LOG.info(e.getMessage());
return;
}
SocketTransportConnection conn = new SocketTransportConnection(s);

View File

@@ -2,6 +2,9 @@ package net.sf.briar.transport;
import static net.sf.briar.api.transport.TransportConstants.MAX_FRAME_LENGTH;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* A thread that calls the writeFullFrame() method of a PaddedConnectionWriter
* at regular intervals. The interval between calls is determined by a target
@@ -10,6 +13,9 @@ import static net.sf.briar.api.transport.TransportConstants.MAX_FRAME_LENGTH;
*/
class FrameScheduler extends Thread {
private static final Logger LOG =
Logger.getLogger(FrameScheduler.class.getName());
private final PaddedConnectionWriter writer;
private final int millisPerFrame;
@@ -27,7 +33,10 @@ class FrameScheduler extends Thread {
if(nextCall > now) {
try {
Thread.sleep(nextCall - now);
} catch(InterruptedException ignored) {}
} catch(InterruptedException e) {
if(LOG.isLoggable(Level.WARNING))
LOG.warning(e.getMessage());
}
}
lastCall = System.currentTimeMillis();
if(!writer.writeFullFrame()) return;

View File

@@ -219,7 +219,10 @@ abstract class StreamConnection implements DatabaseListener {
while(writerFlags == 0) {
try {
wait();
} catch(InterruptedException ignored) {}
} catch(InterruptedException e) {
if(LOG.isLoggable(Level.WARNING))
LOG.warning(e.getMessage());
}
}
flags = writerFlags;
writerFlags = 0;
@@ -256,7 +259,10 @@ abstract class StreamConnection implements DatabaseListener {
while(writerFlags == 0) {
try {
wait();
} catch(InterruptedException ignored) {}
} catch(InterruptedException e) {
if(LOG.isLoggable(Level.WARNING))
LOG.warning(e.getMessage());
}
}
flags = writerFlags;
writerFlags = 0;

View File

@@ -76,7 +76,8 @@ public class LockFairnessTest extends TestCase {
try {
Thread.sleep(sleepTime);
finished.add(this);
} catch(InterruptedException ignored) {
} catch(InterruptedException e) {
e.printStackTrace();
} finally {
lock.readLock().unlock();
}
@@ -99,7 +100,8 @@ public class LockFairnessTest extends TestCase {
try {
Thread.sleep(sleepTime);
finished.add(this);
} catch(InterruptedException ignored) {
} catch(InterruptedException e) {
e.printStackTrace();
} finally {
lock.writeLock().unlock();
}

View File

@@ -737,9 +737,7 @@ public class H2DatabaseTest extends TestCase {
for(int i = 0; i < ids.length; i++) {
db.addOutstandingBatch(txn, contactId, ids[i],
Collections.<MessageId>emptySet());
try {
Thread.sleep(5);
} catch(InterruptedException ignored) {}
Thread.sleep(5);
}
// The contact acks the batches in reverse order. The first
@@ -779,9 +777,7 @@ public class H2DatabaseTest extends TestCase {
for(int i = 0; i < ids.length; i++) {
db.addOutstandingBatch(txn, contactId, ids[i],
Collections.<MessageId>emptySet());
try {
Thread.sleep(5);
} catch(InterruptedException ignored) {}
Thread.sleep(5);
}
// The contact acks the batches in the order they were sent - nothing
@@ -946,9 +942,7 @@ public class H2DatabaseTest extends TestCase {
};
t.start();
// Do whatever the transaction needs to do
try {
Thread.sleep(10);
} catch(InterruptedException ignored) {}
Thread.sleep(10);
transactionFinished.set(true);
// Commit the transaction
db.commitTransaction(txn);
@@ -981,9 +975,7 @@ public class H2DatabaseTest extends TestCase {
};
t.start();
// Do whatever the transaction needs to do
try {
Thread.sleep(10);
} catch(InterruptedException ignored) {}
Thread.sleep(10);
transactionFinished.set(true);
// Abort the transaction
db.abortTransaction(txn);

View File

@@ -1,63 +1,79 @@
package net.sf.briar.plugins.bluetooth;
import java.io.PrintStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import net.sf.briar.api.ContactId;
import net.sf.briar.api.TransportConfig;
import net.sf.briar.api.TransportProperties;
import net.sf.briar.api.plugins.StreamPluginCallback;
import net.sf.briar.api.transport.StreamTransportConnection;
import net.sf.briar.plugins.ImmediateExecutor;
// This is not a JUnit test - it has to be run manually while the server test
// is running on another machine
public class BluetoothClientTest {
public class BluetoothClientTest extends BluetoothTest {
public static final String RESPONSE = "Carrots!";
private final String serverAddress;
BluetoothClientTest(String serverAddress) {
this.serverAddress = serverAddress;
}
void run() throws IOException {
ContactId contactId = new ContactId(0);
ClientCallback callback = new ClientCallback();
// Store the server's Bluetooth address and UUID
TransportProperties p = new TransportProperties();
p.put("address", serverAddress);
p.put("uuid", BluetoothServerTest.UUID);
callback.remote.put(contactId, p);
// Create the plugin
Executor e = Executors.newCachedThreadPool();
BluetoothPlugin plugin = new BluetoothPlugin(e, callback, 0L);
// Start the plugin
System.out.println("Starting plugin");
plugin.start();
// Try to connect to the server
System.out.println("Creating connection");
StreamTransportConnection s = plugin.createConnection(contactId);
if(s == null) {
System.out.println("Connection failed");
} else {
System.out.println("Connection created");
receiveChallengeAndSendResponse(s);
}
// Try to send an invitation
System.out.println("Sending invitation");
s = plugin.sendInvitation(123, INVITATION_TIMEOUT);
if(s == null) {
System.out.println("Connection failed");
} else {
System.out.println("Connection created");
receiveChallengeAndSendResponse(s);
}
// Try to accept an invitation
System.out.println("Accepting invitation");
s = plugin.acceptInvitation(456, INVITATION_TIMEOUT);
if(s == null) {
System.out.println("Connection failed");
} else {
System.out.println("Connection created");
sendChallengeAndReceiveResponse(s);
}
// Stop the plugin
System.out.println("Stopping plugin");
plugin.stop();
}
public static void main(String[] args) throws Exception {
if(args.length != 1) {
System.err.println("Please specify the server's Bluetooth address");
System.exit(1);
}
ContactId contactId = new ContactId(0);
ClientCallback callback = new ClientCallback();
// Store the server's Bluetooth address and UUID
TransportProperties p = new TransportProperties();
p.put("address", args[0]);
p.put("uuid", BluetoothServerTest.UUID);
callback.remote.put(contactId, p);
// Create the plugin
BluetoothPlugin plugin =
new BluetoothPlugin(new ImmediateExecutor(), callback, 0L);
// Start the plugin
System.out.println("Starting plugin");
plugin.start();
// Try to connect to the server
System.out.println("Creating connection");
StreamTransportConnection conn = plugin.createConnection(contactId);
if(conn == null) {
System.out.println("Connection failed");
} else {
System.out.println("Connection created");
Scanner in = new Scanner(conn.getInputStream());
String challenge = in.nextLine();
System.out.println("Received challenge: " + challenge);
if(BluetoothServerTest.CHALLENGE.equals(challenge)) {
PrintStream out = new PrintStream(conn.getOutputStream());
out.println(RESPONSE);
System.out.println("Sent response: " + RESPONSE);
} else {
System.out.println("Incorrect challenge");
}
conn.dispose(true);
}
// Stop the plugin
System.out.println("Stopping plugin");
plugin.stop();
new BluetoothClientTest(args[0]).run();
}
private static class ClientCallback implements StreamPluginCallback {

View File

@@ -1,32 +1,27 @@
package net.sf.briar.plugins.bluetooth;
import java.io.IOException;
import java.io.PrintStream;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import net.sf.briar.api.ContactId;
import net.sf.briar.api.TransportConfig;
import net.sf.briar.api.TransportProperties;
import net.sf.briar.api.plugins.StreamPluginCallback;
import net.sf.briar.api.transport.StreamTransportConnection;
import net.sf.briar.plugins.ImmediateExecutor;
//This is not a JUnit test - it has to be run manually while the server test
//is running on another machine
public class BluetoothServerTest {
public class BluetoothServerTest extends BluetoothTest {
public static final String UUID = "CABBA6E5CABBA6E5CABBA6E5CABBA6E5";
public static final String CHALLENGE = "Potatoes!";
public static void main(String[] args) throws Exception {
void run() throws Exception {
ServerCallback callback = new ServerCallback();
// Store the UUID
callback.config.put("uuid", UUID);
// Create the plugin
BluetoothPlugin plugin =
new BluetoothPlugin(new ImmediateExecutor(), callback, 0L);
Executor e = Executors.newCachedThreadPool();
BluetoothPlugin plugin = new BluetoothPlugin(e, callback, 0L);
// Start the plugin
System.out.println("Starting plugin");
plugin.start();
@@ -35,12 +30,35 @@ public class BluetoothServerTest {
synchronized(callback) {
callback.wait();
}
// Try to accept an invitation
System.out.println("Accepting invitation");
StreamTransportConnection s = plugin.acceptInvitation(123,
INVITATION_TIMEOUT);
if(s == null) {
System.out.println("Connection failed");
} else {
System.out.println("Connection created");
sendChallengeAndReceiveResponse(s);
}
// Try to send an invitation
System.out.println("Sending invitation");
s = plugin.sendInvitation(456, INVITATION_TIMEOUT);
if(s == null) {
System.out.println("Connection failed");
} else {
System.out.println("Connection created");
receiveChallengeAndSendResponse(s);
}
// Stop the plugin
System.out.println("Stopping plugin");
plugin.stop();
}
private static class ServerCallback implements StreamPluginCallback {
public static void main(String[] args) throws Exception {
new BluetoothServerTest().run();
}
private class ServerCallback implements StreamPluginCallback {
private TransportConfig config = new TransportConfig();
private TransportProperties local = new TransportProperties();
@@ -77,24 +95,9 @@ public class BluetoothServerTest {
public void showMessage(String... message) {}
public void incomingConnectionCreated(StreamTransportConnection conn) {
public void incomingConnectionCreated(StreamTransportConnection s) {
System.out.println("Connection received");
try {
PrintStream out = new PrintStream(conn.getOutputStream());
out.println(CHALLENGE);
System.out.println("Sent challenge: " + CHALLENGE);
Scanner in = new Scanner(conn.getInputStream());
String response = in.nextLine();
System.out.println("Received response: " + response);
if(BluetoothClientTest.RESPONSE.equals(response)) {
System.out.println("Correct response");
} else {
System.out.println("Incorrect response");
}
conn.dispose(true);
} catch(IOException e) {
e.printStackTrace();
}
sendChallengeAndReceiveResponse(s);
synchronized(this) {
notifyAll();
}

View File

@@ -0,0 +1,54 @@
package net.sf.briar.plugins.bluetooth;
import java.io.IOException;
import java.io.PrintStream;
import java.util.Scanner;
import net.sf.briar.api.transport.StreamTransportConnection;
abstract class BluetoothTest {
protected static final String UUID = "CABBA6E5CABBA6E5CABBA6E5CABBA6E5";
protected static final String CHALLENGE = "Carrots!";
protected static final String RESPONSE = "Potatoes!";
protected static final long INVITATION_TIMEOUT = 30 * 1000;
void sendChallengeAndReceiveResponse(StreamTransportConnection s) {
try {
PrintStream out = new PrintStream(s.getOutputStream());
out.println(CHALLENGE);
System.out.println("Sent challenge: " + CHALLENGE);
Scanner in = new Scanner(s.getInputStream());
String response = in.nextLine();
System.out.println("Received response: " + response);
if(BluetoothClientTest.RESPONSE.equals(response)) {
System.out.println("Correct response");
} else {
System.out.println("Incorrect response");
}
s.dispose(true);
} catch(IOException e) {
e.printStackTrace();
s.dispose(false);
}
}
void receiveChallengeAndSendResponse(StreamTransportConnection s) {
try {
Scanner in = new Scanner(s.getInputStream());
String challenge = in.nextLine();
System.out.println("Received challenge: " + challenge);
if(BluetoothServerTest.CHALLENGE.equals(challenge)) {
PrintStream out = new PrintStream(s.getOutputStream());
out.println(RESPONSE);
System.out.println("Sent response: " + RESPONSE);
} else {
System.out.println("Incorrect challenge");
}
s.dispose(true);
} catch(IOException e) {
e.printStackTrace();
s.dispose(false);
}
}
}

View File

@@ -339,35 +339,6 @@ public class RemovableDrivePluginTest extends TestCase {
context.assertIsSatisfied();
}
@Test
public void testSmallFileIsIgnored() throws Exception {
Mockery context = new Mockery();
final BatchPluginCallback callback =
context.mock(BatchPluginCallback.class);
final RemovableDriveFinder finder =
context.mock(RemovableDriveFinder.class);
final RemovableDriveMonitor monitor =
context.mock(RemovableDriveMonitor.class);
context.checking(new Expectations() {{
oneOf(monitor).start(with(any(Callback.class)));
}});
RemovableDrivePlugin plugin = new RemovableDrivePlugin(
new ImmediateExecutor(), callback, finder, monitor);
plugin.start();
File f = new File(testDir, "abcdefgh.dat");
OutputStream out = new FileOutputStream(f);
out.write(new byte[TransportConstants.MIN_CONNECTION_LENGTH - 1]);
out.flush();
out.close();
assertEquals(TransportConstants.MIN_CONNECTION_LENGTH - 1, f.length());
plugin.driveInserted(testDir);
context.assertIsSatisfied();
}
@Test
public void testReaderIsCreated() throws Exception {
Mockery context = new Mockery();

View File

@@ -27,13 +27,13 @@ public class SimpleSocketPluginTest extends TestCase {
@Test
public void testIncomingConnection() throws Exception {
StreamCallback callback = new StreamCallback();
callback.local.put("host", "127.0.0.1");
callback.local.put("internal", "127.0.0.1");
callback.local.put("port", "0");
SimpleSocketPlugin plugin =
new SimpleSocketPlugin(new ImmediateExecutor(), callback, 0L);
plugin.start();
// The plugin should have bound a socket and stored the port number
String host = callback.local.get("host");
String host = callback.local.get("internal");
assertNotNull(host);
assertEquals("127.0.0.1", host);
String portString = callback.local.get("port");
@@ -84,7 +84,7 @@ public class SimpleSocketPluginTest extends TestCase {
}.start();
// Tell the plugin about the port
TransportProperties p = new TransportProperties();
p.put("host", "127.0.0.1");
p.put("internal", "127.0.0.1");
p.put("port", String.valueOf(port));
callback.remote.put(contactId, p);
// Connect to the port