mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-20 14:49:53 +01:00
Let the plugin determine whether to flush the output stream after each
packet.
This commit is contained in:
@@ -28,9 +28,8 @@ public interface Plugin {
|
|||||||
long getPollingInterval();
|
long getPollingInterval();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attempts to establish connections using the current transport and
|
* Attempts to establish connections to all contacts, passing any created
|
||||||
* configuration properties, and passes any created connections to the
|
* connections to the callback.
|
||||||
* callback.
|
|
||||||
*/
|
*/
|
||||||
void poll();
|
void poll();
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ import java.io.IOException;
|
|||||||
|
|
||||||
public interface ProtocolWriter {
|
public interface ProtocolWriter {
|
||||||
|
|
||||||
|
void flush() throws IOException;
|
||||||
|
|
||||||
int getMaxBatchesForAck(long capacity);
|
int getMaxBatchesForAck(long capacity);
|
||||||
|
|
||||||
int getMaxMessagesForOffer(long capacity);
|
int getMaxMessagesForOffer(long capacity);
|
||||||
|
|||||||
@@ -4,5 +4,5 @@ import java.io.OutputStream;
|
|||||||
|
|
||||||
public interface ProtocolWriterFactory {
|
public interface ProtocolWriterFactory {
|
||||||
|
|
||||||
ProtocolWriter createProtocolWriter(OutputStream out);
|
ProtocolWriter createProtocolWriter(OutputStream out, boolean flush);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,11 @@ public interface BatchTransportWriter {
|
|||||||
/** Returns an output stream for writing to the transport. */
|
/** Returns an output stream for writing to the transport. */
|
||||||
OutputStream getOutputStream();
|
OutputStream getOutputStream();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the output stream should be flushed after each packet.
|
||||||
|
*/
|
||||||
|
boolean shouldFlush();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Closes the writer and disposes of any associated resources. The
|
* Closes the writer and disposes of any associated resources. The
|
||||||
* argument indicates whether the writer is being closed because of an
|
* argument indicates whether the writer is being closed because of an
|
||||||
|
|||||||
@@ -17,6 +17,11 @@ public interface StreamTransportConnection {
|
|||||||
/** Returns an output stream for writing to the connection. */
|
/** Returns an output stream for writing to the connection. */
|
||||||
OutputStream getOutputStream() throws IOException;
|
OutputStream getOutputStream() throws IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the output stream should be flushed after each packet.
|
||||||
|
*/
|
||||||
|
boolean shouldFlush();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Closes the connection and disposes of any associated resources. The
|
* Closes the connection and disposes of any associated resources. The
|
||||||
* first argument indicates whether the connection is being closed because
|
* first argument indicates whether the connection is being closed because
|
||||||
|
|||||||
@@ -10,19 +10,19 @@ public abstract class AbstractPlugin implements Plugin {
|
|||||||
|
|
||||||
protected final Executor pluginExecutor;
|
protected final Executor pluginExecutor;
|
||||||
|
|
||||||
protected boolean started = false; // Locking: this
|
protected boolean running = false; // Locking: this
|
||||||
|
|
||||||
protected AbstractPlugin(@PluginExecutor Executor pluginExecutor) {
|
protected AbstractPlugin(@PluginExecutor Executor pluginExecutor) {
|
||||||
this.pluginExecutor = pluginExecutor;
|
this.pluginExecutor = pluginExecutor;
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void start() throws IOException {
|
public synchronized void start() throws IOException {
|
||||||
if(started) throw new IllegalStateException();
|
if(running) throw new IllegalStateException();
|
||||||
started = true;
|
running = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void stop() throws IOException {
|
public synchronized void stop() throws IOException {
|
||||||
if(!started) throw new IllegalStateException();
|
if(!running) throw new IllegalStateException();
|
||||||
started = false;
|
running = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -78,30 +78,17 @@ class BluetoothPlugin extends AbstractPlugin implements StreamPlugin {
|
|||||||
}
|
}
|
||||||
throw new IOException(e.toString());
|
throw new IOException(e.toString());
|
||||||
}
|
}
|
||||||
pluginExecutor.execute(createContactSocketBinder());
|
pluginExecutor.execute(new Runnable() {
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public synchronized void stop() throws IOException {
|
|
||||||
super.stop();
|
|
||||||
if(socket != null) {
|
|
||||||
socket.close();
|
|
||||||
socket = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Runnable createContactSocketBinder() {
|
|
||||||
return new Runnable() {
|
|
||||||
public void run() {
|
public void run() {
|
||||||
bindContactSocket();
|
bindContactSocket();
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void bindContactSocket() {
|
private void bindContactSocket() {
|
||||||
String uuid;
|
String uuid;
|
||||||
synchronized(this) {
|
synchronized(this) {
|
||||||
if(!started) return;
|
if(!running) return;
|
||||||
uuid = getUuid();
|
uuid = getUuid();
|
||||||
makeDeviceDiscoverable();
|
makeDeviceDiscoverable();
|
||||||
}
|
}
|
||||||
@@ -115,7 +102,7 @@ class BluetoothPlugin extends AbstractPlugin implements StreamPlugin {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
synchronized(this) {
|
synchronized(this) {
|
||||||
if(!started) {
|
if(!running) {
|
||||||
try {
|
try {
|
||||||
scn.close();
|
scn.close();
|
||||||
} catch(IOException e) {
|
} catch(IOException e) {
|
||||||
@@ -134,7 +121,7 @@ class BluetoothPlugin extends AbstractPlugin implements StreamPlugin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private synchronized String getUuid() {
|
private synchronized String getUuid() {
|
||||||
assert started;
|
assert running;
|
||||||
TransportProperties p = callback.getLocalProperties();
|
TransportProperties p = callback.getLocalProperties();
|
||||||
String uuid = p.get("uuid");
|
String uuid = p.get("uuid");
|
||||||
if(uuid == null) {
|
if(uuid == null) {
|
||||||
@@ -149,7 +136,7 @@ class BluetoothPlugin extends AbstractPlugin implements StreamPlugin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private synchronized void makeDeviceDiscoverable() {
|
private synchronized void makeDeviceDiscoverable() {
|
||||||
assert started;
|
assert running;
|
||||||
// Try to make the device discoverable (requires root on Linux)
|
// Try to make the device discoverable (requires root on Linux)
|
||||||
try {
|
try {
|
||||||
localDevice.setDiscoverable(DiscoveryAgent.GIAC);
|
localDevice.setDiscoverable(DiscoveryAgent.GIAC);
|
||||||
@@ -169,7 +156,7 @@ class BluetoothPlugin extends AbstractPlugin implements StreamPlugin {
|
|||||||
StreamConnectionNotifier scn;
|
StreamConnectionNotifier scn;
|
||||||
StreamConnection s;
|
StreamConnection s;
|
||||||
synchronized(this) {
|
synchronized(this) {
|
||||||
if(!started) return;
|
if(!running) return;
|
||||||
scn = socket;
|
scn = socket;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
@@ -185,6 +172,15 @@ class BluetoothPlugin extends AbstractPlugin implements StreamPlugin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public synchronized void stop() throws IOException {
|
||||||
|
super.stop();
|
||||||
|
if(socket != null) {
|
||||||
|
socket.close();
|
||||||
|
socket = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public boolean shouldPoll() {
|
public boolean shouldPoll() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -193,21 +189,24 @@ class BluetoothPlugin extends AbstractPlugin implements StreamPlugin {
|
|||||||
return pollingInterval;
|
return pollingInterval;
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void poll() {
|
public void poll() {
|
||||||
if(!started) return;
|
synchronized(this) {
|
||||||
pluginExecutor.execute(createConnectors());
|
if(!running) return;
|
||||||
}
|
}
|
||||||
|
pluginExecutor.execute(new Runnable() {
|
||||||
private Runnable createConnectors() {
|
|
||||||
return new Runnable() {
|
|
||||||
public void run() {
|
public void run() {
|
||||||
connectAndCallBack();
|
connectAndCallBack();
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void connectAndCallBack() {
|
private void connectAndCallBack() {
|
||||||
Map<ContactId, String> discovered = discoverContactUrls();
|
Map<ContactId, TransportProperties> remote;
|
||||||
|
synchronized(this) {
|
||||||
|
if(!running) return;
|
||||||
|
remote = callback.getRemoteProperties();
|
||||||
|
}
|
||||||
|
Map<ContactId, String> discovered = discoverContactUrls(remote);
|
||||||
for(Entry<ContactId, String> e : discovered.entrySet()) {
|
for(Entry<ContactId, String> e : discovered.entrySet()) {
|
||||||
ContactId c = e.getKey();
|
ContactId c = e.getKey();
|
||||||
String url = e.getValue();
|
String url = e.getValue();
|
||||||
@@ -216,13 +215,12 @@ class BluetoothPlugin extends AbstractPlugin implements StreamPlugin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Map<ContactId, String> discoverContactUrls() {
|
private Map<ContactId, String> discoverContactUrls(
|
||||||
|
Map<ContactId, TransportProperties> remote) {
|
||||||
DiscoveryAgent discoveryAgent;
|
DiscoveryAgent discoveryAgent;
|
||||||
Map<ContactId, TransportProperties> remote;
|
|
||||||
synchronized(this) {
|
synchronized(this) {
|
||||||
if(!started) return Collections.emptyMap();
|
if(!running) return Collections.emptyMap();
|
||||||
discoveryAgent = localDevice.getDiscoveryAgent();
|
discoveryAgent = localDevice.getDiscoveryAgent();
|
||||||
remote = callback.getRemoteProperties();
|
|
||||||
}
|
}
|
||||||
Map<String, ContactId> addresses = new HashMap<String, ContactId>();
|
Map<String, ContactId> addresses = new HashMap<String, ContactId>();
|
||||||
Map<ContactId, String> uuids = new HashMap<ContactId, String>();
|
Map<ContactId, String> uuids = new HashMap<ContactId, String>();
|
||||||
@@ -236,18 +234,17 @@ class BluetoothPlugin extends AbstractPlugin implements StreamPlugin {
|
|||||||
uuids.put(c, uuid);
|
uuids.put(c, uuid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if(addresses.isEmpty()) return Collections.emptyMap();
|
||||||
ContactListener listener = new ContactListener(discoveryAgent,
|
ContactListener listener = new ContactListener(discoveryAgent,
|
||||||
Collections.unmodifiableMap(addresses),
|
Collections.unmodifiableMap(addresses),
|
||||||
Collections.unmodifiableMap(uuids));
|
Collections.unmodifiableMap(uuids));
|
||||||
synchronized(discoveryLock) {
|
synchronized(discoveryLock) {
|
||||||
try {
|
try {
|
||||||
discoveryAgent.startInquiry(DiscoveryAgent.GIAC, listener);
|
discoveryAgent.startInquiry(DiscoveryAgent.GIAC, listener);
|
||||||
|
return listener.waitForUrls();
|
||||||
} catch(BluetoothStateException e) {
|
} catch(BluetoothStateException e) {
|
||||||
if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.toString());
|
if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.toString());
|
||||||
return Collections.emptyMap();
|
return Collections.emptyMap();
|
||||||
}
|
|
||||||
try {
|
|
||||||
return listener.waitForUrls();
|
|
||||||
} catch(InterruptedException e) {
|
} catch(InterruptedException e) {
|
||||||
if(LOG.isLoggable(Level.INFO))
|
if(LOG.isLoggable(Level.INFO))
|
||||||
LOG.info("Interrupted while waiting for URLs");
|
LOG.info("Interrupted while waiting for URLs");
|
||||||
@@ -259,12 +256,10 @@ class BluetoothPlugin extends AbstractPlugin implements StreamPlugin {
|
|||||||
|
|
||||||
private StreamTransportConnection connect(ContactId c, String url) {
|
private StreamTransportConnection connect(ContactId c, String url) {
|
||||||
synchronized(this) {
|
synchronized(this) {
|
||||||
if(!started) return null;
|
if(!running) return null;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
if(LOG.isLoggable(Level.INFO)) LOG.info("Connecting to " + url);
|
|
||||||
StreamConnection s = (StreamConnection) Connector.open(url);
|
StreamConnection s = (StreamConnection) Connector.open(url);
|
||||||
if(LOG.isLoggable(Level.INFO)) LOG.info("Connected");
|
|
||||||
return new BluetoothTransportConnection(s);
|
return new BluetoothTransportConnection(s);
|
||||||
} catch(IOException e) {
|
} catch(IOException e) {
|
||||||
if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.toString());
|
if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.toString());
|
||||||
@@ -273,7 +268,14 @@ class BluetoothPlugin extends AbstractPlugin implements StreamPlugin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public StreamTransportConnection createConnection(ContactId c) {
|
public StreamTransportConnection createConnection(ContactId c) {
|
||||||
String url = discoverContactUrls().get(c);
|
Map<ContactId, TransportProperties> remote;
|
||||||
|
synchronized(this) {
|
||||||
|
if(!running) return null;
|
||||||
|
remote = callback.getRemoteProperties();
|
||||||
|
}
|
||||||
|
if(!remote.containsKey(c)) return null;
|
||||||
|
remote = Collections.singletonMap(c, remote.get(c));
|
||||||
|
String url = discoverContactUrls(remote).get(c);
|
||||||
return url == null ? null : connect(c, url);
|
return url == null ? null : connect(c, url);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -325,7 +327,7 @@ class BluetoothPlugin extends AbstractPlugin implements StreamPlugin {
|
|||||||
private void createInvitationConnection(ConnectionCallback c) {
|
private void createInvitationConnection(ConnectionCallback c) {
|
||||||
DiscoveryAgent discoveryAgent;
|
DiscoveryAgent discoveryAgent;
|
||||||
synchronized(this) {
|
synchronized(this) {
|
||||||
if(!started) return;
|
if(!running) return;
|
||||||
discoveryAgent = localDevice.getDiscoveryAgent();
|
discoveryAgent = localDevice.getDiscoveryAgent();
|
||||||
}
|
}
|
||||||
// Try to discover the other party until the invitation times out
|
// Try to discover the other party until the invitation times out
|
||||||
@@ -350,7 +352,7 @@ class BluetoothPlugin extends AbstractPlugin implements StreamPlugin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
synchronized(this) {
|
synchronized(this) {
|
||||||
if(!started) return;
|
if(!running) return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(url == null) return;
|
if(url == null) return;
|
||||||
@@ -365,7 +367,7 @@ class BluetoothPlugin extends AbstractPlugin implements StreamPlugin {
|
|||||||
|
|
||||||
private void bindInvitationSocket(final ConnectionCallback c) {
|
private void bindInvitationSocket(final ConnectionCallback c) {
|
||||||
synchronized(this) {
|
synchronized(this) {
|
||||||
if(!started) return;
|
if(!running) return;
|
||||||
makeDeviceDiscoverable();
|
makeDeviceDiscoverable();
|
||||||
}
|
}
|
||||||
// Bind the socket
|
// Bind the socket
|
||||||
@@ -400,7 +402,7 @@ class BluetoothPlugin extends AbstractPlugin implements StreamPlugin {
|
|||||||
private void acceptInvitationConnection(ConnectionCallback c,
|
private void acceptInvitationConnection(ConnectionCallback c,
|
||||||
StreamConnectionNotifier scn) {
|
StreamConnectionNotifier scn) {
|
||||||
synchronized(this) {
|
synchronized(this) {
|
||||||
if(!started) return;
|
if(!running) return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
StreamConnection s = scn.acceptAndOpen();
|
StreamConnection s = scn.acceptAndOpen();
|
||||||
|
|||||||
@@ -29,6 +29,10 @@ class BluetoothTransportConnection implements StreamTransportConnection {
|
|||||||
return stream.openOutputStream();
|
return stream.openOutputStream();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean shouldFlush() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
public void dispose(boolean exception, boolean recognised) {
|
public void dispose(boolean exception, boolean recognised) {
|
||||||
try {
|
try {
|
||||||
stream.close();
|
stream.close();
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ abstract class FilePlugin extends AbstractPlugin implements BatchPlugin {
|
|||||||
|
|
||||||
private BatchTransportWriter createWriter(String filename) {
|
private BatchTransportWriter createWriter(String filename) {
|
||||||
synchronized(this) {
|
synchronized(this) {
|
||||||
if(!started) return null;
|
if(!running) return null;
|
||||||
}
|
}
|
||||||
File dir = chooseOutputDirectory();
|
File dir = chooseOutputDirectory();
|
||||||
if(dir == null || !dir.exists() || !dir.isDirectory()) return null;
|
if(dir == null || !dir.exists() || !dir.isDirectory()) return null;
|
||||||
@@ -86,7 +86,7 @@ abstract class FilePlugin extends AbstractPlugin implements BatchPlugin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected synchronized void createReaderFromFile(final File f) {
|
protected synchronized void createReaderFromFile(final File f) {
|
||||||
if(!started) return;
|
if(!running) return;
|
||||||
pluginExecutor.execute(new ReaderCreator(f));
|
pluginExecutor.execute(new ReaderCreator(f));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -34,6 +34,10 @@ class FileTransportWriter implements BatchTransportWriter {
|
|||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean shouldFlush() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
public void dispose(boolean exception) {
|
public void dispose(boolean exception) {
|
||||||
try {
|
try {
|
||||||
out.close();
|
out.close();
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ implements RemovableDriveMonitor.Callback {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public long getPollingInterval() {
|
public long getPollingInterval() {
|
||||||
return 0L;
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void poll() {
|
public void poll() {
|
||||||
|
|||||||
@@ -53,19 +53,20 @@ class SimpleSocketPlugin extends SocketPlugin {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Socket createClientSocket() throws IOException {
|
protected Socket createClientSocket() throws IOException {
|
||||||
assert started;
|
assert running;
|
||||||
return new Socket();
|
return new Socket();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected ServerSocket createServerSocket() throws IOException {
|
protected ServerSocket createServerSocket() throws IOException {
|
||||||
assert started;
|
assert running;
|
||||||
return new ServerSocket();
|
return new ServerSocket();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Locking: this
|
||||||
@Override
|
@Override
|
||||||
protected synchronized SocketAddress getLocalSocketAddress() {
|
protected SocketAddress getLocalSocketAddress() {
|
||||||
assert started;
|
assert running;
|
||||||
SocketAddress addr = createSocketAddress(callback.getLocalProperties());
|
SocketAddress addr = createSocketAddress(callback.getLocalProperties());
|
||||||
if(addr == null) {
|
if(addr == null) {
|
||||||
try {
|
try {
|
||||||
@@ -87,9 +88,10 @@ class SimpleSocketPlugin extends SocketPlugin {
|
|||||||
boolean link = addr.isLinkLocalAddress();
|
boolean link = addr.isLinkLocalAddress();
|
||||||
boolean site = addr.isSiteLocalAddress();
|
boolean site = addr.isSiteLocalAddress();
|
||||||
if(lan == (link || site)) {
|
if(lan == (link || site)) {
|
||||||
if(LOG.isLoggable(Level.INFO))
|
if(LOG.isLoggable(Level.INFO)) {
|
||||||
LOG.info("Choosing interface "
|
LOG.info("Choosing interface "
|
||||||
+ addr.getHostAddress());
|
+ addr.getHostAddress());
|
||||||
|
}
|
||||||
return addr;
|
return addr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -99,9 +101,10 @@ class SimpleSocketPlugin extends SocketPlugin {
|
|||||||
for(NetworkInterface iface : ifaces) {
|
for(NetworkInterface iface : ifaces) {
|
||||||
for(InetAddress addr : Collections.list(iface.getInetAddresses())) {
|
for(InetAddress addr : Collections.list(iface.getInetAddresses())) {
|
||||||
if(!addr.isLoopbackAddress()) {
|
if(!addr.isLoopbackAddress()) {
|
||||||
if(LOG.isLoggable(Level.INFO))
|
if(LOG.isLoggable(Level.INFO)) {
|
||||||
LOG.info("Accepting interface "
|
LOG.info("Accepting interface "
|
||||||
+ addr.getHostAddress());
|
+ addr.getHostAddress());
|
||||||
|
}
|
||||||
return addr;
|
return addr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -109,16 +112,17 @@ class SimpleSocketPlugin extends SocketPlugin {
|
|||||||
throw new IOException("No suitable interfaces");
|
throw new IOException("No suitable interfaces");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Locking: this
|
||||||
@Override
|
@Override
|
||||||
protected synchronized SocketAddress getRemoteSocketAddress(ContactId c) {
|
protected SocketAddress getRemoteSocketAddress(ContactId c) {
|
||||||
assert started;
|
assert running;
|
||||||
TransportProperties p = callback.getRemoteProperties().get(c);
|
TransportProperties p = callback.getRemoteProperties().get(c);
|
||||||
return p == null ? null : createSocketAddress(p);
|
return p == null ? null : createSocketAddress(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
private synchronized SocketAddress createSocketAddress(
|
// Locking: this
|
||||||
TransportProperties p) {
|
private SocketAddress createSocketAddress(TransportProperties p) {
|
||||||
assert started;
|
assert running;
|
||||||
assert p != null;
|
assert p != null;
|
||||||
String host = p.get("external");
|
String host = p.get("external");
|
||||||
if(host == null) host = p.get("internal");
|
if(host == null) host = p.get("internal");
|
||||||
@@ -133,9 +137,10 @@ class SimpleSocketPlugin extends SocketPlugin {
|
|||||||
return new InetSocketAddress(host, port);
|
return new InetSocketAddress(host, port);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Locking: this
|
||||||
@Override
|
@Override
|
||||||
protected synchronized void setLocalSocketAddress(SocketAddress s) {
|
protected void setLocalSocketAddress(SocketAddress s) {
|
||||||
assert started;
|
assert running;
|
||||||
if(!(s instanceof InetSocketAddress))
|
if(!(s instanceof InetSocketAddress))
|
||||||
throw new IllegalArgumentException();
|
throw new IllegalArgumentException();
|
||||||
InetSocketAddress i = (InetSocketAddress) s;
|
InetSocketAddress i = (InetSocketAddress) s;
|
||||||
|
|||||||
@@ -4,11 +4,13 @@ import java.io.IOException;
|
|||||||
import java.net.ServerSocket;
|
import java.net.ServerSocket;
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
import java.net.SocketAddress;
|
import java.net.SocketAddress;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import net.sf.briar.api.ContactId;
|
import net.sf.briar.api.ContactId;
|
||||||
|
import net.sf.briar.api.TransportProperties;
|
||||||
import net.sf.briar.api.plugins.PluginExecutor;
|
import net.sf.briar.api.plugins.PluginExecutor;
|
||||||
import net.sf.briar.api.plugins.StreamPlugin;
|
import net.sf.briar.api.plugins.StreamPlugin;
|
||||||
import net.sf.briar.api.plugins.StreamPluginCallback;
|
import net.sf.briar.api.plugins.StreamPluginCallback;
|
||||||
@@ -54,7 +56,7 @@ abstract class SocketPlugin extends AbstractPlugin implements StreamPlugin {
|
|||||||
ServerSocket ss = null;
|
ServerSocket ss = null;
|
||||||
try {
|
try {
|
||||||
synchronized(this) {
|
synchronized(this) {
|
||||||
if(!started) return;
|
if(!running) return;
|
||||||
addr = getLocalSocketAddress();
|
addr = getLocalSocketAddress();
|
||||||
ss = createServerSocket();
|
ss = createServerSocket();
|
||||||
if(addr == null || ss == null) return;
|
if(addr == null || ss == null) return;
|
||||||
@@ -77,7 +79,7 @@ abstract class SocketPlugin extends AbstractPlugin implements StreamPlugin {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
synchronized(this) {
|
synchronized(this) {
|
||||||
if(!started) {
|
if(!running) {
|
||||||
try {
|
try {
|
||||||
ss.close();
|
ss.close();
|
||||||
} catch(IOException e) {
|
} catch(IOException e) {
|
||||||
@@ -93,7 +95,7 @@ abstract class SocketPlugin extends AbstractPlugin implements StreamPlugin {
|
|||||||
while(true) {
|
while(true) {
|
||||||
Socket s;
|
Socket s;
|
||||||
synchronized(this) {
|
synchronized(this) {
|
||||||
if(!started) return;
|
if(!running) return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
s = ss.accept();
|
s = ss.accept();
|
||||||
@@ -119,21 +121,19 @@ abstract class SocketPlugin extends AbstractPlugin implements StreamPlugin {
|
|||||||
if(socket != null) socket.close();
|
if(socket != null) socket.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void poll() {
|
public void poll() {
|
||||||
// Subclasses may not support polling
|
Map<ContactId, TransportProperties> remote;
|
||||||
if(!shouldPoll()) throw new UnsupportedOperationException();
|
synchronized(this) {
|
||||||
if(!started) return;
|
if(!running) return;
|
||||||
for(ContactId c : callback.getRemoteProperties().keySet()) {
|
remote = callback.getRemoteProperties();
|
||||||
pluginExecutor.execute(createConnector(c));
|
}
|
||||||
|
for(final ContactId c : remote.keySet()) {
|
||||||
|
pluginExecutor.execute(new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
connectAndCallBack(c);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private Runnable createConnector(final ContactId c) {
|
|
||||||
return new Runnable() {
|
|
||||||
public void run() {
|
|
||||||
connectAndCallBack(c);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void connectAndCallBack(ContactId c) {
|
private void connectAndCallBack(ContactId c) {
|
||||||
@@ -146,7 +146,7 @@ abstract class SocketPlugin extends AbstractPlugin implements StreamPlugin {
|
|||||||
Socket s;
|
Socket s;
|
||||||
try {
|
try {
|
||||||
synchronized(this) {
|
synchronized(this) {
|
||||||
if(!started) return null;
|
if(!running) return null;
|
||||||
addr = getRemoteSocketAddress(c);
|
addr = getRemoteSocketAddress(c);
|
||||||
s = createClientSocket();
|
s = createClientSocket();
|
||||||
if(addr == null || s == null) return null;
|
if(addr == null || s == null) return null;
|
||||||
|
|||||||
@@ -28,6 +28,10 @@ class SocketTransportConnection implements StreamTransportConnection {
|
|||||||
return socket.getOutputStream();
|
return socket.getOutputStream();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean shouldFlush() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
public void dispose(boolean exception, boolean recognised) {
|
public void dispose(boolean exception, boolean recognised) {
|
||||||
try {
|
try {
|
||||||
socket.close();
|
socket.close();
|
||||||
|
|||||||
@@ -21,7 +21,8 @@ class ProtocolWriterFactoryImpl implements ProtocolWriterFactory {
|
|||||||
this.writerFactory = writerFactory;
|
this.writerFactory = writerFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ProtocolWriter createProtocolWriter(OutputStream out) {
|
public ProtocolWriter createProtocolWriter(OutputStream out,
|
||||||
return new ProtocolWriterImpl(serial, writerFactory, out);
|
boolean flush) {
|
||||||
|
return new ProtocolWriterImpl(serial, writerFactory, out, flush);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,12 +27,14 @@ class ProtocolWriterImpl implements ProtocolWriter {
|
|||||||
|
|
||||||
private final SerialComponent serial;
|
private final SerialComponent serial;
|
||||||
private final OutputStream out;
|
private final OutputStream out;
|
||||||
|
private final boolean flush;
|
||||||
private final Writer w;
|
private final Writer w;
|
||||||
|
|
||||||
ProtocolWriterImpl(SerialComponent serial, WriterFactory writerFactory,
|
ProtocolWriterImpl(SerialComponent serial, WriterFactory writerFactory,
|
||||||
OutputStream out) {
|
OutputStream out, boolean flush) {
|
||||||
this.serial = serial;
|
this.serial = serial;
|
||||||
this.out = out;
|
this.out = out;
|
||||||
|
this.flush = flush;
|
||||||
w = writerFactory.createWriter(out);
|
w = writerFactory.createWriter(out);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -67,6 +69,7 @@ class ProtocolWriterImpl implements ProtocolWriter {
|
|||||||
w.writeListStart();
|
w.writeListStart();
|
||||||
for(BatchId b : a.getBatchIds()) w.writeBytes(b.getBytes());
|
for(BatchId b : a.getBatchIds()) w.writeBytes(b.getBytes());
|
||||||
w.writeListEnd();
|
w.writeListEnd();
|
||||||
|
if(flush) out.flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeBatch(RawBatch b) throws IOException {
|
public void writeBatch(RawBatch b) throws IOException {
|
||||||
@@ -74,6 +77,7 @@ class ProtocolWriterImpl implements ProtocolWriter {
|
|||||||
w.writeListStart();
|
w.writeListStart();
|
||||||
for(byte[] raw : b.getMessages()) out.write(raw);
|
for(byte[] raw : b.getMessages()) out.write(raw);
|
||||||
w.writeListEnd();
|
w.writeListEnd();
|
||||||
|
if(flush) out.flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeOffer(Offer o) throws IOException {
|
public void writeOffer(Offer o) throws IOException {
|
||||||
@@ -81,6 +85,7 @@ class ProtocolWriterImpl implements ProtocolWriter {
|
|||||||
w.writeListStart();
|
w.writeListStart();
|
||||||
for(MessageId m : o.getMessageIds()) w.writeBytes(m.getBytes());
|
for(MessageId m : o.getMessageIds()) w.writeBytes(m.getBytes());
|
||||||
w.writeListEnd();
|
w.writeListEnd();
|
||||||
|
if(flush) out.flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeRequest(Request r) throws IOException {
|
public void writeRequest(Request r) throws IOException {
|
||||||
@@ -100,6 +105,7 @@ class ProtocolWriterImpl implements ProtocolWriter {
|
|||||||
w.writeStructId(Types.REQUEST);
|
w.writeStructId(Types.REQUEST);
|
||||||
w.writeUint7((byte) (bytes * 8 - length));
|
w.writeUint7((byte) (bytes * 8 - length));
|
||||||
w.writeBytes(bitmap);
|
w.writeBytes(bitmap);
|
||||||
|
if(flush) out.flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeSubscriptionUpdate(SubscriptionUpdate s)
|
public void writeSubscriptionUpdate(SubscriptionUpdate s)
|
||||||
@@ -112,6 +118,7 @@ class ProtocolWriterImpl implements ProtocolWriter {
|
|||||||
}
|
}
|
||||||
w.writeMapEnd();
|
w.writeMapEnd();
|
||||||
w.writeInt64(s.getTimestamp());
|
w.writeInt64(s.getTimestamp());
|
||||||
|
if(flush) out.flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void writeGroup(Writer w, Group g) throws IOException {
|
private void writeGroup(Writer w, Group g) throws IOException {
|
||||||
@@ -133,5 +140,10 @@ class ProtocolWriterImpl implements ProtocolWriter {
|
|||||||
}
|
}
|
||||||
w.writeListEnd();
|
w.writeListEnd();
|
||||||
w.writeInt64(t.getTimestamp());
|
w.writeInt64(t.getTimestamp());
|
||||||
|
if(flush) out.flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void flush() throws IOException {
|
||||||
|
out.flush();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -55,7 +55,8 @@ class OutgoingBatchConnection {
|
|||||||
transport.getOutputStream(), transport.getCapacity(),
|
transport.getOutputStream(), transport.getCapacity(),
|
||||||
ctx.getSecret());
|
ctx.getSecret());
|
||||||
OutputStream out = conn.getOutputStream();
|
OutputStream out = conn.getOutputStream();
|
||||||
ProtocolWriter writer = protoFactory.createProtocolWriter(out);
|
ProtocolWriter writer = protoFactory.createProtocolWriter(out,
|
||||||
|
transport.shouldFlush());
|
||||||
// There should be enough space for a packet
|
// There should be enough space for a packet
|
||||||
long capacity = conn.getRemainingCapacity();
|
long capacity = conn.getRemainingCapacity();
|
||||||
if(capacity < MAX_PACKET_LENGTH) throw new EOFException();
|
if(capacity < MAX_PACKET_LENGTH) throw new EOFException();
|
||||||
@@ -88,8 +89,7 @@ class OutgoingBatchConnection {
|
|||||||
capacity = writer.getMessageCapacityForBatch(capacity);
|
capacity = writer.getMessageCapacityForBatch(capacity);
|
||||||
b = db.generateBatch(contactId, (int) capacity);
|
b = db.generateBatch(contactId, (int) capacity);
|
||||||
}
|
}
|
||||||
// Flush the output stream
|
writer.flush();
|
||||||
out.flush();
|
|
||||||
transport.dispose(false);
|
transport.dispose(false);
|
||||||
} catch(DbException e) {
|
} catch(DbException e) {
|
||||||
if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.toString());
|
if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.toString());
|
||||||
|
|||||||
@@ -26,11 +26,11 @@ class IncomingStreamConnection extends StreamConnection {
|
|||||||
ConnectionWriterFactory connWriterFactory,
|
ConnectionWriterFactory connWriterFactory,
|
||||||
ProtocolReaderFactory protoReaderFactory,
|
ProtocolReaderFactory protoReaderFactory,
|
||||||
ProtocolWriterFactory protoWriterFactory,
|
ProtocolWriterFactory protoWriterFactory,
|
||||||
ConnectionContext ctx, StreamTransportConnection connection,
|
ConnectionContext ctx, StreamTransportConnection transport,
|
||||||
byte[] tag) {
|
byte[] tag) {
|
||||||
super(dbExecutor, verificationExecutor, db, connReaderFactory,
|
super(dbExecutor, verificationExecutor, db, connReaderFactory,
|
||||||
connWriterFactory, protoReaderFactory, protoWriterFactory,
|
connWriterFactory, protoReaderFactory, protoWriterFactory,
|
||||||
ctx.getContactId(), connection);
|
ctx.getContactId(), transport);
|
||||||
this.ctx = ctx;
|
this.ctx = ctx;
|
||||||
this.tag = tag;
|
this.tag = tag;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,10 +31,10 @@ class OutgoingStreamConnection extends StreamConnection {
|
|||||||
ProtocolReaderFactory protoReaderFactory,
|
ProtocolReaderFactory protoReaderFactory,
|
||||||
ProtocolWriterFactory protoWriterFactory, ContactId contactId,
|
ProtocolWriterFactory protoWriterFactory, ContactId contactId,
|
||||||
TransportIndex transportIndex,
|
TransportIndex transportIndex,
|
||||||
StreamTransportConnection connection) {
|
StreamTransportConnection transport) {
|
||||||
super(dbExecutor, verificationExecutor, db, connReaderFactory,
|
super(dbExecutor, verificationExecutor, db, connReaderFactory,
|
||||||
connWriterFactory, protoReaderFactory, protoWriterFactory,
|
connWriterFactory, protoReaderFactory, protoWriterFactory,
|
||||||
contactId, connection);
|
contactId, transport);
|
||||||
this.transportIndex = transportIndex;
|
this.transportIndex = transportIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -191,7 +191,8 @@ abstract class StreamConnection implements DatabaseListener {
|
|||||||
try {
|
try {
|
||||||
db.addListener(this);
|
db.addListener(this);
|
||||||
OutputStream out = createConnectionWriter().getOutputStream();
|
OutputStream out = createConnectionWriter().getOutputStream();
|
||||||
writer = protoWriterFactory.createProtocolWriter(out);
|
writer = protoWriterFactory.createProtocolWriter(out,
|
||||||
|
transport.shouldFlush());
|
||||||
// Send the initial packets: transports, subs, acks, offer
|
// Send the initial packets: transports, subs, acks, offer
|
||||||
dbExecutor.execute(new GenerateTransportUpdate());
|
dbExecutor.execute(new GenerateTransportUpdate());
|
||||||
dbExecutor.execute(new GenerateSubscriptionUpdate());
|
dbExecutor.execute(new GenerateSubscriptionUpdate());
|
||||||
@@ -203,6 +204,7 @@ abstract class StreamConnection implements DatabaseListener {
|
|||||||
if(task == CLOSE) break;
|
if(task == CLOSE) break;
|
||||||
task.run();
|
task.run();
|
||||||
}
|
}
|
||||||
|
writer.flush();
|
||||||
if(!disposed.getAndSet(true)) transport.dispose(false, true);
|
if(!disposed.getAndSet(true)) transport.dispose(false, true);
|
||||||
} catch(DbException e) {
|
} catch(DbException e) {
|
||||||
if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.toString());
|
if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.toString());
|
||||||
|
|||||||
@@ -77,53 +77,58 @@ class ConnectionDispatcherImpl implements ConnectionDispatcher {
|
|||||||
|
|
||||||
private class DispatchBatchConnection implements Runnable {
|
private class DispatchBatchConnection implements Runnable {
|
||||||
|
|
||||||
private final TransportId t;
|
private final TransportId transportId;
|
||||||
private final BatchTransportReader r;
|
private final BatchTransportReader transport;
|
||||||
|
|
||||||
private DispatchBatchConnection(TransportId t, BatchTransportReader r) {
|
private DispatchBatchConnection(TransportId transportId,
|
||||||
this.t = t;
|
BatchTransportReader transport) {
|
||||||
this.r = r;
|
this.transportId = transportId;
|
||||||
|
this.transport = transport;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void run() {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
byte[] tag = readTag(r.getInputStream());
|
byte[] tag = readTag(transport.getInputStream());
|
||||||
ConnectionContext ctx = recogniser.acceptConnection(t, tag);
|
ConnectionContext ctx = recogniser.acceptConnection(transportId,
|
||||||
if(ctx == null) r.dispose(false, false);
|
tag);
|
||||||
else batchConnFactory.createIncomingConnection(ctx, r, tag);
|
if(ctx == null) transport.dispose(false, false);
|
||||||
|
else batchConnFactory.createIncomingConnection(ctx, transport,
|
||||||
|
tag);
|
||||||
} catch(DbException e) {
|
} catch(DbException e) {
|
||||||
if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.toString());
|
if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.toString());
|
||||||
r.dispose(true, false);
|
transport.dispose(true, false);
|
||||||
} catch(IOException e) {
|
} catch(IOException e) {
|
||||||
if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.toString());
|
if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.toString());
|
||||||
r.dispose(true, false);
|
transport.dispose(true, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class DispatchStreamConnection implements Runnable {
|
private class DispatchStreamConnection implements Runnable {
|
||||||
|
|
||||||
private final TransportId t;
|
private final TransportId transportId;
|
||||||
private final StreamTransportConnection s;
|
private final StreamTransportConnection transport;
|
||||||
|
|
||||||
private DispatchStreamConnection(TransportId t,
|
private DispatchStreamConnection(TransportId transportId,
|
||||||
StreamTransportConnection s) {
|
StreamTransportConnection transport) {
|
||||||
this.t = t;
|
this.transportId = transportId;
|
||||||
this.s = s;
|
this.transport = transport;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void run() {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
byte[] tag = readTag(s.getInputStream());
|
byte[] tag = readTag(transport.getInputStream());
|
||||||
ConnectionContext ctx = recogniser.acceptConnection(t, tag);
|
ConnectionContext ctx = recogniser.acceptConnection(transportId,
|
||||||
if(ctx == null) s.dispose(false, false);
|
tag);
|
||||||
else streamConnFactory.createIncomingConnection(ctx, s, tag);
|
if(ctx == null) transport.dispose(false, false);
|
||||||
|
else streamConnFactory.createIncomingConnection(ctx, transport,
|
||||||
|
tag);
|
||||||
} catch(DbException e) {
|
} catch(DbException e) {
|
||||||
if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.toString());
|
if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.toString());
|
||||||
s.dispose(true, false);
|
transport.dispose(true, false);
|
||||||
} catch(IOException e) {
|
} catch(IOException e) {
|
||||||
if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.toString());
|
if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.toString());
|
||||||
s.dispose(true, false);
|
transport.dispose(true, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -139,10 +139,11 @@ public class ProtocolIntegrationTest extends TestCase {
|
|||||||
ConnectionWriter conn = connectionWriterFactory.createConnectionWriter(
|
ConnectionWriter conn = connectionWriterFactory.createConnectionWriter(
|
||||||
out, Long.MAX_VALUE, secret.clone());
|
out, Long.MAX_VALUE, secret.clone());
|
||||||
OutputStream out1 = conn.getOutputStream();
|
OutputStream out1 = conn.getOutputStream();
|
||||||
ProtocolWriter proto = protocolWriterFactory.createProtocolWriter(out1);
|
ProtocolWriter writer = protocolWriterFactory.createProtocolWriter(out1,
|
||||||
|
false);
|
||||||
|
|
||||||
Ack a = packetFactory.createAck(Collections.singletonList(ack));
|
Ack a = packetFactory.createAck(Collections.singletonList(ack));
|
||||||
proto.writeAck(a);
|
writer.writeAck(a);
|
||||||
|
|
||||||
Collection<byte[]> batch = Arrays.asList(new byte[][] {
|
Collection<byte[]> batch = Arrays.asList(new byte[][] {
|
||||||
message.getSerialised(),
|
message.getSerialised(),
|
||||||
@@ -151,7 +152,7 @@ public class ProtocolIntegrationTest extends TestCase {
|
|||||||
message3.getSerialised()
|
message3.getSerialised()
|
||||||
});
|
});
|
||||||
RawBatch b = packetFactory.createBatch(batch);
|
RawBatch b = packetFactory.createBatch(batch);
|
||||||
proto.writeBatch(b);
|
writer.writeBatch(b);
|
||||||
|
|
||||||
Collection<MessageId> offer = Arrays.asList(new MessageId[] {
|
Collection<MessageId> offer = Arrays.asList(new MessageId[] {
|
||||||
message.getId(),
|
message.getId(),
|
||||||
@@ -160,13 +161,13 @@ public class ProtocolIntegrationTest extends TestCase {
|
|||||||
message3.getId()
|
message3.getId()
|
||||||
});
|
});
|
||||||
Offer o = packetFactory.createOffer(offer);
|
Offer o = packetFactory.createOffer(offer);
|
||||||
proto.writeOffer(o);
|
writer.writeOffer(o);
|
||||||
|
|
||||||
BitSet requested = new BitSet(4);
|
BitSet requested = new BitSet(4);
|
||||||
requested.set(1);
|
requested.set(1);
|
||||||
requested.set(3);
|
requested.set(3);
|
||||||
Request r = packetFactory.createRequest(requested, 4);
|
Request r = packetFactory.createRequest(requested, 4);
|
||||||
proto.writeRequest(r);
|
writer.writeRequest(r);
|
||||||
|
|
||||||
// Use a LinkedHashMap for predictable iteration order
|
// Use a LinkedHashMap for predictable iteration order
|
||||||
Map<Group, Long> subs = new LinkedHashMap<Group, Long>();
|
Map<Group, Long> subs = new LinkedHashMap<Group, Long>();
|
||||||
@@ -174,13 +175,13 @@ public class ProtocolIntegrationTest extends TestCase {
|
|||||||
subs.put(group1, 0L);
|
subs.put(group1, 0L);
|
||||||
SubscriptionUpdate s = packetFactory.createSubscriptionUpdate(subs,
|
SubscriptionUpdate s = packetFactory.createSubscriptionUpdate(subs,
|
||||||
timestamp);
|
timestamp);
|
||||||
proto.writeSubscriptionUpdate(s);
|
writer.writeSubscriptionUpdate(s);
|
||||||
|
|
||||||
TransportUpdate t = packetFactory.createTransportUpdate(transports,
|
TransportUpdate t = packetFactory.createTransportUpdate(transports,
|
||||||
timestamp);
|
timestamp);
|
||||||
proto.writeTransportUpdate(t);
|
writer.writeTransportUpdate(t);
|
||||||
|
|
||||||
out1.flush();
|
writer.flush();
|
||||||
return out.toByteArray();
|
return out.toByteArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -188,20 +189,19 @@ public class ProtocolIntegrationTest extends TestCase {
|
|||||||
InputStream in = new ByteArrayInputStream(connectionData);
|
InputStream in = new ByteArrayInputStream(connectionData);
|
||||||
byte[] tag = new byte[TAG_LENGTH];
|
byte[] tag = new byte[TAG_LENGTH];
|
||||||
assertEquals(TAG_LENGTH, in.read(tag, 0, TAG_LENGTH));
|
assertEquals(TAG_LENGTH, in.read(tag, 0, TAG_LENGTH));
|
||||||
ConnectionReader r = connectionReaderFactory.createConnectionReader(in,
|
ConnectionReader conn = connectionReaderFactory.createConnectionReader(
|
||||||
secret.clone(), tag);
|
in, secret.clone(), tag);
|
||||||
in = r.getInputStream();
|
InputStream in1 = conn.getInputStream();
|
||||||
ProtocolReader protocolReader =
|
ProtocolReader reader = protocolReaderFactory.createProtocolReader(in1);
|
||||||
protocolReaderFactory.createProtocolReader(in);
|
|
||||||
|
|
||||||
// Read the ack
|
// Read the ack
|
||||||
assertTrue(protocolReader.hasAck());
|
assertTrue(reader.hasAck());
|
||||||
Ack a = protocolReader.readAck();
|
Ack a = reader.readAck();
|
||||||
assertEquals(Collections.singletonList(ack), a.getBatchIds());
|
assertEquals(Collections.singletonList(ack), a.getBatchIds());
|
||||||
|
|
||||||
// Read and verify the batch
|
// Read and verify the batch
|
||||||
assertTrue(protocolReader.hasBatch());
|
assertTrue(reader.hasBatch());
|
||||||
Batch b = protocolReader.readBatch().verify();
|
Batch b = reader.readBatch().verify();
|
||||||
Collection<Message> messages = b.getMessages();
|
Collection<Message> messages = b.getMessages();
|
||||||
assertEquals(4, messages.size());
|
assertEquals(4, messages.size());
|
||||||
Iterator<Message> it = messages.iterator();
|
Iterator<Message> it = messages.iterator();
|
||||||
@@ -211,8 +211,8 @@ public class ProtocolIntegrationTest extends TestCase {
|
|||||||
checkMessageEquality(message3, it.next());
|
checkMessageEquality(message3, it.next());
|
||||||
|
|
||||||
// Read the offer
|
// Read the offer
|
||||||
assertTrue(protocolReader.hasOffer());
|
assertTrue(reader.hasOffer());
|
||||||
Offer o = protocolReader.readOffer();
|
Offer o = reader.readOffer();
|
||||||
Collection<MessageId> offered = o.getMessageIds();
|
Collection<MessageId> offered = o.getMessageIds();
|
||||||
assertEquals(4, offered.size());
|
assertEquals(4, offered.size());
|
||||||
Iterator<MessageId> it1 = offered.iterator();
|
Iterator<MessageId> it1 = offered.iterator();
|
||||||
@@ -222,8 +222,8 @@ public class ProtocolIntegrationTest extends TestCase {
|
|||||||
assertEquals(message3.getId(), it1.next());
|
assertEquals(message3.getId(), it1.next());
|
||||||
|
|
||||||
// Read the request
|
// Read the request
|
||||||
assertTrue(protocolReader.hasRequest());
|
assertTrue(reader.hasRequest());
|
||||||
Request req = protocolReader.readRequest();
|
Request req = reader.readRequest();
|
||||||
BitSet requested = req.getBitmap();
|
BitSet requested = req.getBitmap();
|
||||||
assertFalse(requested.get(0));
|
assertFalse(requested.get(0));
|
||||||
assertTrue(requested.get(1));
|
assertTrue(requested.get(1));
|
||||||
@@ -233,8 +233,8 @@ public class ProtocolIntegrationTest extends TestCase {
|
|||||||
assertEquals(2, requested.cardinality());
|
assertEquals(2, requested.cardinality());
|
||||||
|
|
||||||
// Read the subscription update
|
// Read the subscription update
|
||||||
assertTrue(protocolReader.hasSubscriptionUpdate());
|
assertTrue(reader.hasSubscriptionUpdate());
|
||||||
SubscriptionUpdate s = protocolReader.readSubscriptionUpdate();
|
SubscriptionUpdate s = reader.readSubscriptionUpdate();
|
||||||
Map<Group, Long> subs = s.getSubscriptions();
|
Map<Group, Long> subs = s.getSubscriptions();
|
||||||
assertEquals(2, subs.size());
|
assertEquals(2, subs.size());
|
||||||
assertEquals(Long.valueOf(0L), subs.get(group));
|
assertEquals(Long.valueOf(0L), subs.get(group));
|
||||||
@@ -242,8 +242,8 @@ public class ProtocolIntegrationTest extends TestCase {
|
|||||||
assertTrue(s.getTimestamp() == timestamp);
|
assertTrue(s.getTimestamp() == timestamp);
|
||||||
|
|
||||||
// Read the transport update
|
// Read the transport update
|
||||||
assertTrue(protocolReader.hasTransportUpdate());
|
assertTrue(reader.hasTransportUpdate());
|
||||||
TransportUpdate t = protocolReader.readTransportUpdate();
|
TransportUpdate t = reader.readTransportUpdate();
|
||||||
assertEquals(transports, t.getTransports());
|
assertEquals(transports, t.getTransports());
|
||||||
assertTrue(t.getTimestamp() == timestamp);
|
assertTrue(t.getTimestamp() == timestamp);
|
||||||
|
|
||||||
|
|||||||
@@ -84,7 +84,8 @@ public class ConstantsTest extends TestCase {
|
|||||||
private void testBatchesFitIntoAck(int length) throws Exception {
|
private void testBatchesFitIntoAck(int length) throws Exception {
|
||||||
// Create an ack with as many batch IDs as possible
|
// Create an ack with as many batch IDs as possible
|
||||||
ByteArrayOutputStream out = new ByteArrayOutputStream(length);
|
ByteArrayOutputStream out = new ByteArrayOutputStream(length);
|
||||||
ProtocolWriter writer = protocolWriterFactory.createProtocolWriter(out);
|
ProtocolWriter writer = protocolWriterFactory.createProtocolWriter(out,
|
||||||
|
true);
|
||||||
int maxBatches = writer.getMaxBatchesForAck(length);
|
int maxBatches = writer.getMaxBatchesForAck(length);
|
||||||
Collection<BatchId> acked = new ArrayList<BatchId>();
|
Collection<BatchId> acked = new ArrayList<BatchId>();
|
||||||
for(int i = 0; i < maxBatches; i++) {
|
for(int i = 0; i < maxBatches; i++) {
|
||||||
@@ -116,7 +117,8 @@ public class ConstantsTest extends TestCase {
|
|||||||
// Add the message to a batch
|
// Add the message to a batch
|
||||||
ByteArrayOutputStream out =
|
ByteArrayOutputStream out =
|
||||||
new ByteArrayOutputStream(MAX_PACKET_LENGTH);
|
new ByteArrayOutputStream(MAX_PACKET_LENGTH);
|
||||||
ProtocolWriter writer = protocolWriterFactory.createProtocolWriter(out);
|
ProtocolWriter writer = protocolWriterFactory.createProtocolWriter(out,
|
||||||
|
true);
|
||||||
RawBatch b = packetFactory.createBatch(Collections.singletonList(
|
RawBatch b = packetFactory.createBatch(Collections.singletonList(
|
||||||
message.getSerialised()));
|
message.getSerialised()));
|
||||||
writer.writeBatch(b);
|
writer.writeBatch(b);
|
||||||
@@ -140,7 +142,8 @@ public class ConstantsTest extends TestCase {
|
|||||||
private void testMessagesFitIntoOffer(int length) throws Exception {
|
private void testMessagesFitIntoOffer(int length) throws Exception {
|
||||||
// Create an offer with as many message IDs as possible
|
// Create an offer with as many message IDs as possible
|
||||||
ByteArrayOutputStream out = new ByteArrayOutputStream(length);
|
ByteArrayOutputStream out = new ByteArrayOutputStream(length);
|
||||||
ProtocolWriter writer = protocolWriterFactory.createProtocolWriter(out);
|
ProtocolWriter writer = protocolWriterFactory.createProtocolWriter(out,
|
||||||
|
true);
|
||||||
int maxMessages = writer.getMaxMessagesForOffer(length);
|
int maxMessages = writer.getMaxMessagesForOffer(length);
|
||||||
Collection<MessageId> offered = new ArrayList<MessageId>();
|
Collection<MessageId> offered = new ArrayList<MessageId>();
|
||||||
for(int i = 0; i < maxMessages; i++) {
|
for(int i = 0; i < maxMessages; i++) {
|
||||||
@@ -165,7 +168,8 @@ public class ConstantsTest extends TestCase {
|
|||||||
// Add the subscriptions to an update
|
// Add the subscriptions to an update
|
||||||
ByteArrayOutputStream out =
|
ByteArrayOutputStream out =
|
||||||
new ByteArrayOutputStream(MAX_PACKET_LENGTH);
|
new ByteArrayOutputStream(MAX_PACKET_LENGTH);
|
||||||
ProtocolWriter writer = protocolWriterFactory.createProtocolWriter(out);
|
ProtocolWriter writer = protocolWriterFactory.createProtocolWriter(out,
|
||||||
|
true);
|
||||||
SubscriptionUpdate s = packetFactory.createSubscriptionUpdate(subs,
|
SubscriptionUpdate s = packetFactory.createSubscriptionUpdate(subs,
|
||||||
Long.MAX_VALUE);
|
Long.MAX_VALUE);
|
||||||
writer.writeSubscriptionUpdate(s);
|
writer.writeSubscriptionUpdate(s);
|
||||||
@@ -194,7 +198,8 @@ public class ConstantsTest extends TestCase {
|
|||||||
// Add the transports to an update
|
// Add the transports to an update
|
||||||
ByteArrayOutputStream out =
|
ByteArrayOutputStream out =
|
||||||
new ByteArrayOutputStream(MAX_PACKET_LENGTH);
|
new ByteArrayOutputStream(MAX_PACKET_LENGTH);
|
||||||
ProtocolWriter writer = protocolWriterFactory.createProtocolWriter(out);
|
ProtocolWriter writer = protocolWriterFactory.createProtocolWriter(out,
|
||||||
|
true);
|
||||||
TransportUpdate t = packetFactory.createTransportUpdate(transports,
|
TransportUpdate t = packetFactory.createTransportUpdate(transports,
|
||||||
Long.MAX_VALUE);
|
Long.MAX_VALUE);
|
||||||
writer.writeTransportUpdate(t);
|
writer.writeTransportUpdate(t);
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ public class ProtocolReadWriteTest extends TestCase {
|
|||||||
public void testWriteAndRead() throws Exception {
|
public void testWriteAndRead() throws Exception {
|
||||||
// Write
|
// Write
|
||||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
ProtocolWriter writer = writerFactory.createProtocolWriter(out);
|
ProtocolWriter writer = writerFactory.createProtocolWriter(out, true);
|
||||||
|
|
||||||
Ack a = packetFactory.createAck(Collections.singletonList(batchId));
|
Ack a = packetFactory.createAck(Collections.singletonList(batchId));
|
||||||
writer.writeAck(a);
|
writer.writeAck(a);
|
||||||
|
|||||||
@@ -37,7 +37,8 @@ public class ProtocolWriterImplTest extends TestCase {
|
|||||||
@Test
|
@Test
|
||||||
public void testWriteBitmapNoPadding() throws IOException {
|
public void testWriteBitmapNoPadding() throws IOException {
|
||||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
ProtocolWriter w = new ProtocolWriterImpl(serial, writerFactory, out);
|
ProtocolWriter w = new ProtocolWriterImpl(serial, writerFactory, out,
|
||||||
|
true);
|
||||||
BitSet b = new BitSet();
|
BitSet b = new BitSet();
|
||||||
// 11011001 = 0xD9
|
// 11011001 = 0xD9
|
||||||
b.set(0);
|
b.set(0);
|
||||||
@@ -61,7 +62,8 @@ public class ProtocolWriterImplTest extends TestCase {
|
|||||||
@Test
|
@Test
|
||||||
public void testWriteBitmapWithPadding() throws IOException {
|
public void testWriteBitmapWithPadding() throws IOException {
|
||||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
ProtocolWriter w = new ProtocolWriterImpl(serial, writerFactory, out);
|
ProtocolWriter w = new ProtocolWriterImpl(serial, writerFactory, out,
|
||||||
|
true);
|
||||||
BitSet b = new BitSet();
|
BitSet b = new BitSet();
|
||||||
// 01011001 = 0x59
|
// 01011001 = 0x59
|
||||||
b.set(1);
|
b.set(1);
|
||||||
|
|||||||
@@ -112,7 +112,7 @@ public class BatchConnectionReadWriteTest extends TestCase {
|
|||||||
ProtocolWriterFactory protoFactory =
|
ProtocolWriterFactory protoFactory =
|
||||||
alice.getInstance(ProtocolWriterFactory.class);
|
alice.getInstance(ProtocolWriterFactory.class);
|
||||||
TestBatchTransportWriter transport = new TestBatchTransportWriter(out,
|
TestBatchTransportWriter transport = new TestBatchTransportWriter(out,
|
||||||
Long.MAX_VALUE);
|
Long.MAX_VALUE, false);
|
||||||
OutgoingBatchConnection batchOut = new OutgoingBatchConnection(db,
|
OutgoingBatchConnection batchOut = new OutgoingBatchConnection(db,
|
||||||
connFactory, protoFactory, contactId, transportIndex,
|
connFactory, protoFactory, contactId, transportIndex,
|
||||||
transport);
|
transport);
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ public class OutgoingBatchConnectionTest extends TestCase {
|
|||||||
public void testConnectionTooShort() throws Exception {
|
public void testConnectionTooShort() throws Exception {
|
||||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
TestBatchTransportWriter transport = new TestBatchTransportWriter(out,
|
TestBatchTransportWriter transport = new TestBatchTransportWriter(out,
|
||||||
ProtocolConstants.MAX_PACKET_LENGTH);
|
ProtocolConstants.MAX_PACKET_LENGTH, true);
|
||||||
OutgoingBatchConnection connection = new OutgoingBatchConnection(db,
|
OutgoingBatchConnection connection = new OutgoingBatchConnection(db,
|
||||||
connFactory, protoFactory, contactId, transportIndex,
|
connFactory, protoFactory, contactId, transportIndex,
|
||||||
transport);
|
transport);
|
||||||
@@ -97,7 +97,7 @@ public class OutgoingBatchConnectionTest extends TestCase {
|
|||||||
public void testNothingToSend() throws Exception {
|
public void testNothingToSend() throws Exception {
|
||||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
TestBatchTransportWriter transport = new TestBatchTransportWriter(out,
|
TestBatchTransportWriter transport = new TestBatchTransportWriter(out,
|
||||||
TransportConstants.MIN_CONNECTION_LENGTH);
|
TransportConstants.MIN_CONNECTION_LENGTH, true);
|
||||||
OutgoingBatchConnection connection = new OutgoingBatchConnection(db,
|
OutgoingBatchConnection connection = new OutgoingBatchConnection(db,
|
||||||
connFactory, protoFactory, contactId, transportIndex,
|
connFactory, protoFactory, contactId, transportIndex,
|
||||||
transport);
|
transport);
|
||||||
@@ -133,7 +133,7 @@ public class OutgoingBatchConnectionTest extends TestCase {
|
|||||||
public void testSomethingToSend() throws Exception {
|
public void testSomethingToSend() throws Exception {
|
||||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
TestBatchTransportWriter transport = new TestBatchTransportWriter(out,
|
TestBatchTransportWriter transport = new TestBatchTransportWriter(out,
|
||||||
TransportConstants.MIN_CONNECTION_LENGTH);
|
TransportConstants.MIN_CONNECTION_LENGTH, true);
|
||||||
OutgoingBatchConnection connection = new OutgoingBatchConnection(db,
|
OutgoingBatchConnection connection = new OutgoingBatchConnection(db,
|
||||||
connFactory, protoFactory, contactId, transportIndex,
|
connFactory, protoFactory, contactId, transportIndex,
|
||||||
transport);
|
transport);
|
||||||
|
|||||||
@@ -9,12 +9,15 @@ class TestBatchTransportWriter implements BatchTransportWriter {
|
|||||||
|
|
||||||
private final ByteArrayOutputStream out;
|
private final ByteArrayOutputStream out;
|
||||||
private final long capacity;
|
private final long capacity;
|
||||||
|
private final boolean flush;
|
||||||
|
|
||||||
private boolean disposed = false, exception = false;
|
private boolean disposed = false, exception = false;
|
||||||
|
|
||||||
TestBatchTransportWriter(ByteArrayOutputStream out, long capacity) {
|
TestBatchTransportWriter(ByteArrayOutputStream out, long capacity,
|
||||||
|
boolean flush) {
|
||||||
this.out = out;
|
this.out = out;
|
||||||
this.capacity = capacity;
|
this.capacity = capacity;
|
||||||
|
this.flush = flush;
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getCapacity() {
|
public long getCapacity() {
|
||||||
@@ -25,6 +28,10 @@ class TestBatchTransportWriter implements BatchTransportWriter {
|
|||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean shouldFlush() {
|
||||||
|
return flush;
|
||||||
|
}
|
||||||
|
|
||||||
public void dispose(boolean exception) {
|
public void dispose(boolean exception) {
|
||||||
assert !disposed;
|
assert !disposed;
|
||||||
disposed = true;
|
disposed = true;
|
||||||
|
|||||||
Reference in New Issue
Block a user