Added Js code (40%)
[iotcloud.git] / src / java / iotcloud / Slot.java
1 package iotcloud;
2 import java.util.Vector;
3 import java.nio.ByteBuffer;
4 import javax.crypto.Mac;
5 import java.util.Arrays;
6
7 /**
8  * Data structuring for holding Slot information.
9  * @author Brian Demsky
10  * @version 1.0
11  */
12
13 class Slot implements Liveness {
14         /** Sets the slot size. */
15         static final int SLOT_SIZE=2048;
16         /** Sets how many bytes we reserve. */
17         static final int RESERVED_SPACE=64;
18         /** Sets the size for the HMAC. */
19         static final int HMAC_SIZE=32;
20
21         /** Sequence number of the slot. */
22         private long seqnum;//
23         /** HMAC of previous slot. */
24         private byte[] prevhmac;
25         /** HMAC of this slot. */
26         private byte[] hmac;
27         /** Machine that sent this slot. */
28         private long machineid;
29         /** Vector of entries in this slot. */
30         private Vector<Entry> entries;
31         /** Pieces of information that are live. */
32         private int livecount;
33         /** Flag that indicates whether this slot is still live for
34          * recording the machine that sent it. */
35         private boolean seqnumlive;
36         /** Number of bytes of free space. */
37         private int freespace;
38
39         Slot(long _seqnum, long _machineid, byte[] _prevhmac, byte[] _hmac) {
40                 seqnum=_seqnum;
41                 machineid=_machineid;
42                 prevhmac=_prevhmac;
43                 hmac=_hmac;
44                 entries=new Vector<Entry>();
45                 livecount=1;
46                 seqnumlive=true;
47                 freespace = SLOT_SIZE - getBaseSize();
48         }
49
50         Slot(long _seqnum, long _machineid, byte[] _prevhmac) {
51                 this(_seqnum, _machineid, _prevhmac, null);
52         }
53
54         Slot(long _seqnum, long _machineid) {
55                 this(_seqnum, _machineid, new byte[HMAC_SIZE], null);
56         }
57
58         byte[] getHMAC() {
59                 return hmac;
60         }
61
62         byte[] getPrevHMAC() {
63                 return prevhmac;
64         }
65
66         void addEntry(Entry e) {
67                 e=e.getCopy(this);
68                 entries.add(e);
69                 livecount++;
70                 freespace -= e.getSize();
71         }
72
73         private void addShallowEntry(Entry e) {
74                 entries.add(e);
75                 livecount++;
76                 freespace -= e.getSize();
77         }
78
79         /**
80          * Returns true if the slot has free space to hold the entry without
81          * using its reserved space. */
82
83         boolean hasSpace(Entry e) {
84                 int newfreespace = freespace - e.getSize();
85                 return newfreespace > RESERVED_SPACE;
86         }
87
88         /**
89          * Returns true if the slot can fit the entry potentially using the
90          * reserved space. */
91
92         boolean canFit(Entry e) {
93                 int newfreespace = freespace - e.getSize();
94                 return newfreespace >= 0;
95         }
96
97         Vector<Entry> getEntries() {
98                 return entries;
99         }
100
101         static Slot decode(byte[] array, Mac mac) {
102                 mac.update(array, HMAC_SIZE, array.length-HMAC_SIZE);
103                 byte[] realmac=mac.doFinal();
104
105                 ByteBuffer bb=ByteBuffer.wrap(array);
106                 byte[] hmac=new byte[HMAC_SIZE];
107                 byte[] prevhmac=new byte[HMAC_SIZE];
108                 bb.get(hmac);
109                 bb.get(prevhmac);
110                 if (!Arrays.equals(realmac, hmac))
111                         throw new Error("Server Error: Invalid HMAC!  Potential Attack!");
112
113                 long seqnum=bb.getLong();
114                 long machineid=bb.getLong();
115                 int numentries=bb.getInt();
116                 Slot slot=new Slot(seqnum, machineid, prevhmac, hmac);
117
118                 for(int i=0; i<numentries; i++) {
119                         slot.addShallowEntry(Entry.decode(slot, bb));
120                 }
121
122                 return slot;
123         }
124
125         byte[] encode(Mac mac) {
126                 byte[] array=new byte[SLOT_SIZE];
127                 ByteBuffer bb=ByteBuffer.wrap(array);
128                 /* Leave space for the slot HMAC.  */
129                 bb.position(HMAC_SIZE);
130                 bb.put(prevhmac);
131                 bb.putLong(seqnum);
132                 bb.putLong(machineid);
133                 bb.putInt(entries.size());
134                 for(Entry entry:entries) {
135                         entry.encode(bb);
136                 }
137                 /* Compute our HMAC */
138                 mac.update(array, HMAC_SIZE, array.length-HMAC_SIZE);
139                 byte[] realmac=mac.doFinal();
140                 hmac = realmac;
141                 bb.position(0);
142                 bb.put(realmac);
143                 return array;
144         }
145
146         /**
147          * Returns the empty size of a Slot. Includes 2 HMACs, the machine
148          * identifier, the sequence number, and the number of entries.
149          */
150         int getBaseSize() {
151                 return 2*HMAC_SIZE+2*Long.BYTES+Integer.BYTES;
152         }
153
154         /**
155          * Returns the live set of entries for this Slot.  Generates a fake
156          * LastMessage entry to represent the information stored by the slot
157          * itself.
158          */
159
160         Vector<Entry> getLiveEntries() {
161                 Vector<Entry> liveEntries=new Vector<Entry>();
162                 for(Entry entry: entries) {
163                         if (entry.isLive())
164                                 liveEntries.add(entry);
165                 }
166                         
167                 if (seqnumlive)
168                         liveEntries.add(new LastMessage(this, machineid, seqnum));
169
170                 return liveEntries;
171         }
172
173         /**
174          * Returns the sequence number of the slot.
175          */
176
177         long getSequenceNumber() {
178                 return seqnum;
179         }
180
181         /**
182          * Returns the machine that sent this slot.
183          */
184
185         long getMachineID() {
186                 return machineid;
187         }
188
189         /**
190          * Records that a newer slot records the fact that this slot was
191          * sent by the relevant machine.
192          */
193
194         void setDead() {
195                 seqnumlive=false;
196                 decrementLiveCount();
197         }
198
199         /**
200          * Update the count of live entries.
201          */
202
203         void decrementLiveCount() {
204                 livecount--;
205                 Vector<Entry> e=getLiveEntries();
206         }
207
208         /**
209          * Returns whether the slot stores any live information.
210          */
211
212         boolean isLive() {
213                 return livecount > 0;
214         }
215
216         public String toString() {
217                 return "<"+getSequenceNumber()+">";
218         }
219 }