diff --git a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/protocol/MailboxMessage.java b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/protocol/MailboxMessage.java index 39c952ebfbf7a073adcba4fbdbe40aae7606fe5f..96396e17537333b11c45724760484863580fd87e 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/protocol/MailboxMessage.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/protocol/MailboxMessage.java @@ -3,27 +3,52 @@ package org.briarproject.bramble.mailbox.protocol; import org.briarproject.bramble.api.FormatException; import org.briarproject.bramble.api.data.BdfList; +import java.net.ProtocolException; + /** * MailboxRPCMessages are serialized as BdfLists and formatted as follows: - * + * <p> * Requests (BODY depending on TYPE): * [TYPE, MESSAGE_ID, [BODY]] * [long, long [BdfList]] - * + * <p> * Error Responses: * [TYPE, MESSAGE_ID, [false, ERROR_MSG]] * [long, long, [boolean, string]] - * + * <p> * Successful Responses (BODY depending on TYPE): * [TYPE, MESSAGE_ID, [true, [BODY]]] * [long, long, [boolean, [BdfList]]] */ public interface MailboxMessage { + static MailboxMessage parse(BdfList msg) throws ProtocolException { + try { + TYPE mType = TYPE.fromLong(msg.getLong(0)); + switch (mType) { + case RESPONSE: + return new MailboxResponse(msg); + case SYNC: + return new MailboxRequestSync(msg); + case TAKE: + return new MailboxRequestTake(msg); + case END: + return new MailboxRequestEnd(msg); + case STORE: + return new MailboxRequestStore(msg); + default: + throw new ProtocolException( + "Unknown message Type received"); + } + } catch (FormatException e) { + throw new ProtocolException("Invalid MailboxMessageReceived"); + } + } + /** * @return Message ID which uniquely identifies a Request and is used to * match responses to a request. - * + * <p> * (NOTE: This identifier is only unique for "active" requests, which * wer sent and await a response. Replay protection must be provided by the * underlying protocol!) @@ -48,8 +73,6 @@ public interface MailboxMessage { BdfList toBdfList(); /** - * - * * @param list * @throws FormatException */ @@ -68,9 +91,10 @@ public interface MailboxMessage { this.value = value; } - public static TYPE fromLong(long b) throws IllegalArgumentException{ - if (b > TYPE.values().length){ - throw new IllegalArgumentException("Invalid Mailbox Message Type"); + public static TYPE fromLong(long b) throws IllegalArgumentException { + if (b > TYPE.values().length) { + throw new IllegalArgumentException( + "Invalid Mailbox Message Type"); } return TYPE.values()[(int) b]; } diff --git a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/protocol/MailboxProtocol.java b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/protocol/MailboxProtocol.java index 12fbff73d7ec8e6f9f0e90eb97be40ce3b685160..7df043a439d28f4ed5273c8b829b5aab4ca928d9 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/protocol/MailboxProtocol.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/protocol/MailboxProtocol.java @@ -1,10 +1,8 @@ package org.briarproject.bramble.mailbox.protocol; -import org.briarproject.bramble.api.FormatException; import org.briarproject.bramble.api.data.BdfList; import org.briarproject.bramble.api.data.BdfReader; import org.briarproject.bramble.api.data.BdfWriter; -import org.briarproject.bramble.mailbox.protocol.MailboxMessage.TYPE; import java.io.EOFException; import java.io.IOException; @@ -37,7 +35,6 @@ public class MailboxProtocol implements Runnable { volatile BlockingQueue<MailboxRequest> inQueue = new LinkedBlockingQueue<>(); - volatile ConcurrentHashMap<Long, MailboxRequest> pendingRequests = new ConcurrentHashMap<>(); @@ -54,6 +51,13 @@ public class MailboxProtocol implements Runnable { } + public void sendKeepAlive() throws IOException { + // flush the writer without pending data to send a keepalive + synchronized (mailboxBdfWriter) { + mailboxBdfWriter.flush(); + } + } + public void writeRequest(MailboxMessage req) throws InterruptedException, IOException { if (req.hasResponse()) @@ -124,19 +128,33 @@ public class MailboxProtocol implements Runnable { } try { - mailboxMessage = parseMessage(bdfMsg); + mailboxMessage = MailboxMessage.parse(bdfMsg); } catch (ProtocolException e) { LOG.info(e.toString()); continue; } - if (mailboxMessage.getType() == RESPONSE) { + if (mailboxMessage.getType() == RESPONSE) handleResponse((MailboxResponse) mailboxMessage); - continue; - } + else + inQueue.add((MailboxRequest) mailboxMessage); + } + } + + private void handleResponse(MailboxResponse msg) { + MailboxRequest req = pendingRequests.remove(msg.getId()); - inQueue.add((MailboxRequest) mailboxMessage); + if (req == null) { + if (LOG.isLoggable(WARNING)) + LOG.warning("Received response not matching with any request"); + return; } + + if (msg.isSuccess()) + req.signalSucess(); + else + req.signalError(msg.getErrorMessage()); + } private void writeOutgoingMessages() { @@ -153,18 +171,19 @@ public class MailboxProtocol implements Runnable { return; } - try { - mailboxBdfWriter.writeList(message.toBdfList()); - mailboxBdfWriter.flush(); - } catch (IOException e) { - writingThread.interrupt(); - handleIOException(false, e); - return; + synchronized (mailboxBdfWriter) { + try { + mailboxBdfWriter.writeList(message.toBdfList()); + mailboxBdfWriter.flush(); + } catch (IOException e) { + writingThread.interrupt(); + handleIOException(false, e); + return; + } } } } - private void handleIOException(boolean isReadingThread, IOException e) { if (isReadingThread && writingThread != null) writingThread.interrupt(); @@ -191,43 +210,5 @@ public class MailboxProtocol implements Runnable { } } - private MailboxMessage parseMessage(BdfList msg) throws ProtocolException { - try { - TYPE mType = TYPE.fromLong(msg.getLong(0)); - switch (mType) { - case RESPONSE: - return new MailboxResponse(msg); - case SYNC: - return new MailboxRequestSync(msg); - case TAKE: - return new MailboxRequestTake(msg); - case END: - return new MailboxRequestEnd(msg); - case STORE: - return new MailboxRequestStore(msg); - default: - throw new ProtocolException( - "Unknown message Type received"); - } - } catch (FormatException e) { - throw new ProtocolException("Invalid MailboxMessageReceived"); - } - } - - private void handleResponse(MailboxResponse msg) { - MailboxRequest req = pendingRequests.remove(msg.getId()); - - if (req == null) { - if (LOG.isLoggable(WARNING)) - LOG.warning("Received response not matching with any request"); - return; - } - - if (msg.isSuccess()) - req.signalSucess(); - else - req.signalError(msg.getErrorMessage()); - - } } diff --git a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/protocol/MailboxRequest.java b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/protocol/MailboxRequest.java index 1a6313eabfbc6fbcd15335712a4d921f85f56150..c0b02470758712fa9df44daf644017a3d9c00865 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/protocol/MailboxRequest.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/protocol/MailboxRequest.java @@ -3,9 +3,8 @@ package org.briarproject.bramble.mailbox.protocol; import org.briarproject.bramble.api.FormatException; import org.briarproject.bramble.api.data.BdfList; -import java.util.Arrays; -import java.util.Random; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicLong; public abstract class MailboxRequest implements MailboxMessage { @@ -16,11 +15,11 @@ public abstract class MailboxRequest implements MailboxMessage { private AtomicBoolean responseReceived = new AtomicBoolean(false); private boolean wasSuccessful = false; + static AtomicLong msgIdCounter = new AtomicLong(); + public MailboxRequest(TYPE type) { this.type = type; - // msgid may as well be a counter here.. - Random random = new Random(); - msgId = random.nextLong(); + this.msgId = msgIdCounter.getAndIncrement(); } public MailboxRequest(BdfList lst) throws FormatException { @@ -31,8 +30,7 @@ public abstract class MailboxRequest implements MailboxMessage { @Override public BdfList toBdfList() { - return new BdfList( - Arrays.asList(type.getValue(), getId(), getRequestBody())); + return BdfList.of(type.getValue(), getId(), getRequestBody()); } @Override @@ -75,9 +73,8 @@ public abstract class MailboxRequest implements MailboxMessage { "Attempting to wait for a response of a request with no response"); synchronized (responseReceived) { - while (!responseReceived.get()) { + while (!responseReceived.get()) responseReceived.wait(); - } } return wasSuccessful; diff --git a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/protocol/MailboxRequestStore.java b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/protocol/MailboxRequestStore.java index f94f6e4946214d8ec1abc24b7912ad88fb934ec2..83cc85a86c54c33093a3cf693357959fad53e07e 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/protocol/MailboxRequestStore.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/protocol/MailboxRequestStore.java @@ -4,9 +4,6 @@ import org.briarproject.bramble.api.FormatException; import org.briarproject.bramble.api.contact.ContactId; import org.briarproject.bramble.api.data.BdfList; -import java.io.IOException; -import java.util.Arrays; - import static org.briarproject.bramble.mailbox.protocol.MailboxMessage.TYPE.STORE; public class MailboxRequestStore extends MailboxRequest { @@ -25,8 +22,7 @@ public class MailboxRequestStore extends MailboxRequest { } public BdfList getRequestBody() { - return new BdfList(Arrays.asList(contactId.getInt(), - encryptedSyncStream)); + return BdfList.of(contactId.getInt(), encryptedSyncStream); } @Override diff --git a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/protocol/MailboxRequestSync.java b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/protocol/MailboxRequestSync.java index 7a69e135a53933df6f6f00d294aabf31099f0483..9d5fa51c5c2265fee545817990910108e6b89453 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/protocol/MailboxRequestSync.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/protocol/MailboxRequestSync.java @@ -3,15 +3,14 @@ package org.briarproject.bramble.mailbox.protocol; import org.briarproject.bramble.api.FormatException; import org.briarproject.bramble.api.data.BdfList; -import java.io.IOException; -import java.util.Arrays; - public class MailboxRequestSync extends MailboxRequest { private byte[] encryptedStream; + private boolean endOfStream; - public MailboxRequestSync(byte [] encryptedStream) { + public MailboxRequestSync(byte[] encryptedStream, boolean endOfStream) { super(TYPE.SYNC); this.encryptedStream = encryptedStream; + this.endOfStream = endOfStream; } public MailboxRequestSync(BdfList lst) throws FormatException { @@ -20,10 +19,9 @@ public class MailboxRequestSync extends MailboxRequest { @Override protected BdfList getRequestBody() { - return new BdfList(Arrays.asList(encryptedStream)); + return BdfList.of(encryptedStream, endOfStream); } - @Override public boolean hasResponse() { return false; @@ -32,9 +30,14 @@ public class MailboxRequestSync extends MailboxRequest { @Override public void parseBody(BdfList list) throws FormatException { this.encryptedStream = list.getRaw(0); + this.endOfStream = list.getBoolean(1); } public byte[] getSyncStream() { return encryptedStream; } + + public boolean isEndOfStream() { + return endOfStream; + } } diff --git a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/protocol/MailboxRequestTake.java b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/protocol/MailboxRequestTake.java index a1ccd2ecbc59bbb9f36cb35234cc858b7d0d56ba..6fe0b80ac2664674789905b92eb02dd591c7df16 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/protocol/MailboxRequestTake.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/protocol/MailboxRequestTake.java @@ -4,14 +4,11 @@ import org.briarproject.bramble.api.FormatException; import org.briarproject.bramble.api.contact.ContactId; import org.briarproject.bramble.api.data.BdfList; -import java.io.IOException; -import java.util.Arrays; - public class MailboxRequestTake extends MailboxRequest { private ContactId contactId; - private byte [] encryptedSyncStream = null; + private byte[] encryptedSyncStream = null; - public MailboxRequestTake(ContactId contactId,byte [] encryptedSyncStream){ + public MailboxRequestTake(ContactId contactId, byte[] encryptedSyncStream) { super(TYPE.TAKE); this.contactId = contactId; this.encryptedSyncStream = encryptedSyncStream; @@ -21,10 +18,9 @@ public class MailboxRequestTake extends MailboxRequest { super(msg); } - @Override protected BdfList getRequestBody() { - return new BdfList(Arrays.asList(contactId.getInt(), encryptedSyncStream)); + return BdfList.of(contactId.getInt(), encryptedSyncStream); } @Override diff --git a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/protocol/MailboxResponse.java b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/protocol/MailboxResponse.java index 077b8ee69336a2d588ec355b48f928fc0df06cd6..0febf4634f14ae0fdcf8868713fd84d00ebcd7bd 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/protocol/MailboxResponse.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/protocol/MailboxResponse.java @@ -3,8 +3,6 @@ package org.briarproject.bramble.mailbox.protocol; import org.briarproject.bramble.api.FormatException; import org.briarproject.bramble.api.data.BdfList; -import java.util.Arrays; - import javax.annotation.Nullable; import static org.briarproject.bramble.mailbox.protocol.MailboxMessage.TYPE.RESPONSE; @@ -46,21 +44,20 @@ public class MailboxResponse implements MailboxMessage { @Override public BdfList toBdfList() { BdfList body; - if (!success) { - body = new BdfList(Arrays.asList(success, errorMessage)); - } else { - body = new BdfList(Arrays.asList(success)); - } - return new BdfList(Arrays.asList(RESPONSE.getValue(), msgId, body)); + if (!success) + body = BdfList.of(success, errorMessage); + else + body = BdfList.of(success); + + return BdfList.of(RESPONSE.getValue(), msgId, body); } @Override public void parseBody(BdfList list) throws FormatException { success = list.getBoolean(0); - if (!success) { + if (!success) errorMessage = list.getString(1); - } } public String getErrorMessage() {