package iotcloud;
+import java.nio.ByteBuffer;
-public abstract class Entry {
-
+abstract class Entry {
+ static final byte TypeKeyValue = 1;
+ static final byte TypeLastMessage = 2;
+ static final byte TypeRejectedMessage = 3;
+ static final byte TypeTableStatus = 4;
+
+ static Entry decode(ByteBuffer bb) {
+ byte type=bb.get();
+ switch(type) {
+ case TypeKeyValue:
+ return KeyValue.decode(bb);
+ case TypeLastMessage:
+ return LastMessage.decode(bb);
+ case TypeRejectedMessage:
+ return RejectedMessage.decode(bb);
+ case TypeTableStatus:
+ return TableStatus.decode(bb);
+ default:
+ throw new Error("Unrecognized Entry Type: "+type);
+ }
+ }
+
+ abstract void encode(ByteBuffer bb);
+
+ abstract int getSize();
}
package iotcloud;
+import java.nio.ByteBuffer;
-public class KeyValue extends Entry {
+class KeyValue extends Entry {
+ byte[] key;
+ byte[] value;
+ KeyValue(byte[] _key, byte[] _value) {
+ key=_key;
+ value=_value;
+ }
+ static Entry decode(ByteBuffer bb) {
+ int keylength=bb.getInt();
+ int valuelength=bb.getInt();
+ byte[] key=new byte[keylength];
+ byte[] value=new byte[valuelength];
+ bb.get(key);
+ bb.get(value);
+ return new KeyValue(key, value);
+ }
+ void encode(ByteBuffer bb) {
+ bb.put(Entry.TypeKeyValue);
+ bb.putInt(key.length);
+ bb.putInt(value.length);
+ bb.put(key);
+ bb.put(value);
+ }
+
+ int getSize() {
+ return 2*Integer.BYTES+key.length+value.length+Byte.BYTES;
+ }
}
package iotcloud;
-public class LastMessage extends Entry {
+import java.nio.ByteBuffer;
+class LastMessage extends Entry {
+ private long machineid;
+ private long seqnum;
+
+ LastMessage(long _machineid, long _seqnum) {
+ machineid=_machineid;
+ seqnum=_seqnum;
+ }
+ static Entry decode(ByteBuffer bb) {
+ long machineid=bb.getLong();
+ long seqnum=bb.getLong();
+ return new LastMessage(machineid, seqnum);
+ }
+
+ void encode(ByteBuffer bb) {
+ bb.put(Entry.TypeLastMessage);
+ bb.putLong(machineid);
+ bb.putLong(seqnum);
+ }
+
+ int getSize() {
+ return 2*Long.BYTES+Byte.BYTES;
+ }
}
package iotcloud;
+import java.nio.ByteBuffer;
-public class RejectedMessage extends Entry {
-
+class RejectedMessage extends Entry {
+ private long machineid;
+ private long seqnum;
+ private boolean equalto;
+ RejectedMessage(long _machineid, long _seqnum, boolean _equalto) {
+ machineid=_machineid;
+ seqnum=_seqnum;
+ equalto=_equalto;
+ }
+
+ static Entry decode(ByteBuffer bb) {
+ long machineid=bb.getLong();
+ long seqnum=bb.getLong();
+ byte equalto=bb.get();
+ return new RejectedMessage(machineid, seqnum, equalto==1);
+ }
+
+ void encode(ByteBuffer bb) {
+ bb.put(Entry.TypeRejectedMessage);
+ bb.putLong(machineid);
+ bb.putLong(seqnum);
+ bb.put(equalto?(byte)1:(byte)0);
+ }
+
+ int getSize() {
+ return 2*Long.BYTES + 2*Byte.BYTES;
+ }
}
package iotcloud;
import java.util.Vector;
+import java.nio.ByteBuffer;
+import javax.crypto.Mac;
+import java.util.Arrays;
class Slot {
+ public static final int SLOT_SIZE=2048;
+ public static final int HMAC_SIZE=32;
+
long seqnum;
- byte[] bytes;
+ byte[] prevhmac;
+ byte[] hmac;
+ long machineid;
Vector<Entry> entries;
- Slot() {
- entries=new Vector();
+ Slot(Vector _entries) {
+ entries=_entries;
+ }
+
+ Slot(long _seqnum, long _machineid, byte[] _prevhmac, byte[] _hmac, Vector<Entry> _entries) {
+ seqnum=_seqnum;
+ machineid=_machineid;
+ prevhmac=_prevhmac;
+ hmac=_hmac;
+ entries=_entries;
}
Slot(long _seqnum, byte[] _bytes) {
- this();
seqnum=_seqnum;
- bytes=_bytes;
+ }
+
+ static Slot decode(byte[] array, Mac mac) {
+ mac.update(array, HMAC_SIZE, array.length-HMAC_SIZE);
+ byte[] realmac=mac.doFinal();
+
+ ByteBuffer bb=ByteBuffer.wrap(array);
+ byte[] hmac=new byte[HMAC_SIZE];
+ byte[] prevhmac=new byte[HMAC_SIZE];
+ bb.get(hmac);
+ bb.get(prevhmac);
+ if (!Arrays.equals(realmac, hmac))
+ throw new Error("Invalid HMAC! Potential Attack!");
+
+ long seqnum=bb.getLong();
+ long machineid=bb.getLong();
+ int numentries=bb.getInt();
+ Vector<Entry> entries=new Vector();
+ for(int i=0;i<numentries;i++) {
+ entries.add(Entry.decode(bb));
+ }
+
+ return new Slot(seqnum, machineid, prevhmac, hmac, entries);
+ }
+
+ byte[] encode(Mac mac) {
+ byte[] array=new byte[SLOT_SIZE];
+ ByteBuffer bb=ByteBuffer.wrap(array);
+ bb.position(HMAC_SIZE); //Leave space for the HMACs
+ bb.put(prevhmac);
+ bb.putLong(seqnum);
+ bb.putLong(machineid);
+ bb.putInt(entries.size());
+ for(Entry entry:entries) {
+ entry.encode(bb);
+ }
+ //Compute our HMAC
+ mac.update(array, HMAC_SIZE, array.length-HMAC_SIZE);
+ byte[] realmac=mac.doFinal();
+ bb.position(0);
+ bb.put(realmac);
+ return array;
}
long getSequenceNumber() {
}
byte[] getBytes() {
- return bytes;
+ return null;
}
public String toString() {
--- /dev/null
+package iotcloud;
+
+public class Table {
+ int tablesize;
+
+}
--- /dev/null
+package iotcloud;
+import java.nio.ByteBuffer;
+
+class TableStatus extends Entry {
+ int maxslots;
+
+ TableStatus(int _maxslots) {
+ maxslots=_maxslots;
+ }
+
+ static Entry decode(ByteBuffer bb) {
+ int maxslots=bb.getInt();
+ return new TableStatus(maxslots);
+ }
+
+ void encode(ByteBuffer bb) {
+ bb.put(Entry.TypeTableStatus);
+ bb.putInt(maxslots);
+ }
+
+ int getSize() {
+ return Integer.BYTES+Byte.BYTES;
+ }
+}
requestsequencenumber = strtoll(sequencenumber_str + 1, NULL, 10);
}
}
+
+ //don't allow a really old sequence number
+ if (requestsequencenumber < oldestentry)
+ requestsequencenumber = oldestentry;
/* Update size if we get request */
char * numqueueentries_str = tok_ptr;