}
public Slot[] putSlot(Slot slot, int max) throws IOException{
- long sequencenumber=slot.getSequenceNumber();
- byte[] bytes=slot.encode(mac);
-
- URL url=buildRequest(true, sequencenumber, max);
- URLConnection con=url.openConnection();
- HttpURLConnection http = (HttpURLConnection) con;
- http.setRequestMethod("POST");
- http.setFixedLengthStreamingMode(bytes.length);
- http.setDoOutput(true);
- http.connect();
- OutputStream os=http.getOutputStream();
- os.write(bytes);
- System.out.println(http.getResponseMessage());
-
- InputStream is=http.getInputStream();
- DataInputStream dis=new DataInputStream(is);
- byte[] resptype=new byte[7];
- dis.readFully(resptype);
- if (Arrays.equals(resptype, "getslot".getBytes()))
- return processSlots(dis);
- else if (Arrays.equals(resptype, "putslot".getBytes()))
- return null;
- else
- throw new Error("Bad response to putslot");
+ try {
+ long sequencenumber=slot.getSequenceNumber();
+ byte[] bytes=slot.encode(mac);
+
+ URL url=buildRequest(true, sequencenumber, max);
+ URLConnection con=url.openConnection();
+ HttpURLConnection http = (HttpURLConnection) con;
+ http.setRequestMethod("POST");
+ http.setFixedLengthStreamingMode(bytes.length);
+ http.setDoOutput(true);
+ http.connect();
+ OutputStream os=http.getOutputStream();
+ os.write(bytes);
+ System.out.println(http.getResponseMessage());
+
+ InputStream is=http.getInputStream();
+ DataInputStream dis=new DataInputStream(is);
+ byte[] resptype=new byte[7];
+ dis.readFully(resptype);
+ if (Arrays.equals(resptype, "getslot".getBytes()))
+ return processSlots(dis);
+ else if (Arrays.equals(resptype, "putslot".getBytes()))
+ return null;
+ else
+ throw new Error("Bad response to putslot");
+ } catch (Exception e) {
+ throw new Error("putSlot failed");
+ }
}
- public Slot[] getSlots(long sequencenumber) throws IOException {
- URL url=buildRequest(false, sequencenumber, 0);
- URLConnection con=url.openConnection();
- HttpURLConnection http = (HttpURLConnection) con;
- http.setRequestMethod("POST");
- http.connect();
- System.out.println(http.getResponseMessage());
- InputStream is=http.getInputStream();
-
- DataInputStream dis=new DataInputStream(is);
- byte[] resptype=new byte[7];
- dis.readFully(resptype);
- if (!Arrays.equals(resptype, "getslot".getBytes()))
- throw new Error("Bad Response: "+new String(resptype));
- else
- return processSlots(dis);
+ public Slot[] getSlots(long sequencenumber) {
+ try {
+ URL url=buildRequest(false, sequencenumber, 0);
+ URLConnection con=url.openConnection();
+ HttpURLConnection http = (HttpURLConnection) con;
+ http.setRequestMethod("POST");
+ http.connect();
+ System.out.println(http.getResponseMessage());
+ InputStream is=http.getInputStream();
+
+ DataInputStream dis=new DataInputStream(is);
+ byte[] resptype=new byte[7];
+ dis.readFully(resptype);
+ if (!Arrays.equals(resptype, "getslot".getBytes()))
+ throw new Error("Bad Response: "+new String(resptype));
+ else
+ return processSlots(dis);
+ } catch (Exception e) {
+ throw new Error("getSlots failed");
+ }
}
Slot[] processSlots(DataInputStream dis) throws IOException {
int numberofslots=dis.readInt();
int[] sizesofslots=new int[numberofslots];
Slot[] slots=new Slot[numberofslots];
- System.out.println(numberofslots);
for(int i=0;i<numberofslots;i++)
sizesofslots[i]=dis.readInt();
class RejectedMessage extends Entry {
private long machineid;
- private long seqnum;
+ private long oldseqnum;
+ private long newseqnum;
private boolean equalto;
- RejectedMessage(long _machineid, long _seqnum, boolean _equalto) {
+ RejectedMessage(long _machineid, long _oldseqnum, long _newseqnum, boolean _equalto) {
machineid=_machineid;
- seqnum=_seqnum;
+ oldseqnum=_oldseqnum;
+ newseqnum=_newseqnum;
equalto=_equalto;
}
static Entry decode(ByteBuffer bb) {
long machineid=bb.getLong();
- long seqnum=bb.getLong();
+ long oldseqnum=bb.getLong();
+ long newseqnum=bb.getLong();
byte equalto=bb.get();
- return new RejectedMessage(machineid, seqnum, equalto==1);
+ return new RejectedMessage(machineid, oldseqnum, newseqnum, equalto==1);
}
void encode(ByteBuffer bb) {
bb.put(Entry.TypeRejectedMessage);
bb.putLong(machineid);
- bb.putLong(seqnum);
+ bb.putLong(oldseqnum);
+ bb.putLong(newseqnum);
bb.put(equalto?(byte)1:(byte)0);
}
int getSize() {
- return 2*Long.BYTES + 2*Byte.BYTES;
+ return 3*Long.BYTES + 2*Byte.BYTES;
}
}
--- /dev/null
+package iotcloud;
+
+class SlotBuffer {
+ static final int DEFAULT_SIZE = 128;
+
+ private Slot[] array;
+ private int head;
+ private int tail;
+ private long oldestseqn;
+
+ SlotBuffer() {
+ array=new Slot[DEFAULT_SIZE+1];
+ }
+
+ int size() {
+ if (head >= tail)
+ return head - tail;
+ return (array.length + head) - tail;
+ }
+
+ void resize(int newsize) {
+ if (newsize == (array.length-1))
+ return;
+ Slot[] newarray = new Slot[newsize+1];
+ int currsize = size();
+ int index = tail;
+ for(int i=0; i < currsize; i++) {
+ newarray[i] = array[index];
+ if ((++index) == array.length)
+ index = 0;
+ }
+ array = newarray;
+ tail = currsize;
+ head = 0;
+ }
+
+ void putSlot(Slot s) {
+ array[head]=s;
+ head++;
+ if (oldestseqn==0)
+ oldestseqn = s.getSequenceNumber();
+
+ if (head==tail) {
+ tail++;
+ oldestseqn++;
+ }
+ }
+
+ Slot getSlot(long seqnum) {
+ int diff=(int) (seqnum-oldestseqn);
+ int index=diff + tail;
+ if (index > array.length) {
+ if (head >= tail)
+ return null;
+ index-= array.length;
+ }
+
+ if (index >= array.length ||
+ index >= head)
+ return null;
+
+ return array[index];
+ }
+
+ long getOldestSeqNum() {
+ return oldestseqn;
+ }
+
+ long getNewestSeqNum() {
+ return oldestseqn + size();
+ }
+}
package iotcloud;
import java.util.HashMap;
+import java.util.Arrays;
import javax.crypto.spec.*;
import javax.crypto.*;
public class Table {
int numslots;
- HashMap table=new HashMap();
+ HashMap<IoTString, IoTString> table=new HashMap<IoTString, IoTString>();
+ SlotBuffer buffer;
CloudComm cloud;
private Mac hmac;
+ long sequencenumber;
public Table(String baseurl, String password) {
initCloud(baseurl, password);
+ buffer = new SlotBuffer();
+ sequencenumber = 1;
}
private void initCloud(String baseurl, String password) {
}
}
+ public void update() {
+ Slot[] newslots=cloud.getSlots(sequencenumber);
+ validateandupdate(newslots);
+ }
+
+ void validateandupdate(Slot[] newslots) {
+ //The cloud communication layer has checked slot HMACs already
+ //before decoding
+
+ if (newslots.length==0)
+ return;
+
+ long firstseqnum=newslots[0].getSequenceNumber();
+ if (firstseqnum < sequencenumber)
+ throw new Error("Server sent older slots!");
+
+ checkHMACChain(newslots);
+
+ if (firstseqnum == (buffer.getNewestSeqNum()+1)) {
+ //contiguous update
+ } else {
+ //non-contiguous update
+ }
+
+ }
+
+ void checkHMACChain(Slot[] newslots) {
+ if (newslots[0].getSequenceNumber() == (buffer.getNewestSeqNum()+1)) {
+ Slot prevslot=buffer.getSlot(buffer.getNewestSeqNum());
+ Slot currslot=newslots[0];
+ if (!Arrays.equals(prevslot.getHMAC(), currslot.getPrevHMAC()))
+ throw new Error("Error in HMAC Chain");
+ }
+ for(int i=1; i < newslots.length; i++) {
+ Slot prevslot=newslots[i-1];
+ Slot currslot=newslots[i];
+ if (!Arrays.equals(prevslot.getHMAC(), currslot.getPrevHMAC()))
+ throw new Error("Error in HMAC Chain");
+ }
+ }
+
}