more js
[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 the size for the HMAC. */
17         static final int HMAC_SIZE=32;
18
19         /** Sequence number of the slot. */
20         private long seqnum;//
21         /** HMAC of previous slot. */
22         private byte[] prevhmac;//
23         /** HMAC of this slot. */
24         private byte[] hmac;//
25         /** Machine that sent this slot. */
26         private long machineid;//
27         /** Vector of entries in this slot. */
28         private Vector<Entry> entries;
29         /** Pieces of information that are live. */
30         private int livecount;//
31         /** Flag that indicates whether this slot is still live for
32          * recording the machine that sent it. */
33         private boolean seqnumlive;//
34         /** Number of bytes of free space. */
35         private int freespace;
36         /** Reference to Table */
37         private Table table;
38
39         Slot(Table _table, 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                 table=_table;
49         }
50
51         Slot(Table _table, long _seqnum, long _machineid, byte[] _prevhmac) {
52                 this(_table, _seqnum, _machineid, _prevhmac, null);
53         }
54
55 <<<<<<< HEAD
56         Slot(long _seqnum, long _machineid) {
57                 this(_seqnum, _machineid, new byte[ HMAC_SIZE], null);
58 =======
59         Slot(Table _table, long _seqnum, long _machineid) {
60                 this(_table, _seqnum, _machineid, new byte[HMAC_SIZE], null);
61 >>>>>>> f80cc30f294899f47cef3507334f8ca357862e5e
62         }
63
64         byte[] getHMAC() {
65                 return hmac;
66         }
67
68         byte[] getPrevHMAC() {
69                 return prevhmac;
70         }
71
72         void addEntry(Entry e) {
73                 e=e.getCopy(this);
74                 entries.add(e);
75                 livecount++;
76                 freespace -= e.getSize();
77         }
78
79         private void addShallowEntry(Entry e) {
80                 entries.add(e);
81                 livecount++;
82                 freespace -= e.getSize();
83         }
84
85         /**
86          * Returns true if the slot has free space to hold the entry without
87          * using its reserved space. */
88
89         boolean hasSpace(Entry e) {
90                 int newfreespace = freespace - e.getSize();
91                 return newfreespace >= 0;
92         }
93
94         Vector<Entry> getEntries() {
95                 return entries;
96         }
97
98         static Slot decode(Table table, byte[] array, Mac mac) {
99                 mac.update(array, HMAC_SIZE, array.length-HMAC_SIZE);
100                 byte[] realmac=mac.doFinal();
101
102                 ByteBuffer bb=ByteBuffer.wrap(array);
103                 byte[] hmac=new byte[HMAC_SIZE];
104                 byte[] prevhmac=new byte[HMAC_SIZE];
105                 bb.get(hmac);
106                 bb.get(prevhmac);
107                 if (!Arrays.equals(realmac, hmac))
108                         throw new Error("Server Error: Invalid HMAC!  Potential Attack!");
109
110                 long seqnum=bb.getLong();
111                 long machineid=bb.getLong();
112                 int numentries=bb.getInt();
113                 Slot slot=new Slot(table, seqnum, machineid, prevhmac, hmac);
114
115                 for(int i=0; i<numentries; i++) {
116                         slot.addShallowEntry(Entry.decode(slot, bb));
117                 }
118
119                 return slot;
120         }
121
122         byte[] encode(Mac mac) {
123                 byte[] array=new byte[SLOT_SIZE];
124                 ByteBuffer bb=ByteBuffer.wrap(array);
125                 /* Leave space for the slot HMAC.  */
126                 bb.position(HMAC_SIZE);
127                 bb.put(prevhmac);
128                 bb.putLong(seqnum);
129                 bb.putLong(machineid);
130                 bb.putInt(entries.size());
131                 for(Entry entry:entries) {
132                         entry.encode(bb);
133                 }
134                 /* Compute our HMAC */
135                 mac.update(array, HMAC_SIZE, array.length-HMAC_SIZE);
136                 byte[] realmac=mac.doFinal();
137                 hmac = realmac;
138                 bb.position(0);
139                 bb.put(realmac);
140                 return array;
141         }
142
143         /**
144          * Returns the empty size of a Slot. Includes 2 HMACs, the machine
145          * identifier, the sequence number, and the number of entries.
146          */
147         int getBaseSize() {
148                 return 2*HMAC_SIZE+2*Long.BYTES+Integer.BYTES;
149         }
150
151         /**
152          * Returns the live set of entries for this Slot.  Generates a fake
153          * LastMessage entry to represent the information stored by the slot
154          * itself.
155          */
156
157         Vector<Entry> getLiveEntries(boolean resize) {
158                 Vector<Entry> liveEntries=new Vector<Entry>();
159                 for(Entry entry: entries) {
160                         if (entry.isLive()) {
161                                 if (!resize || entry.getType() != Entry.TypeTableStatus)
162                                         liveEntries.add(entry);
163                         }
164                 }
165                         
166                 if (seqnumlive && !resize)
167                         liveEntries.add(new LastMessage(this, machineid, seqnum));
168
169                 return liveEntries;
170         }
171
172         /**
173          * Returns the sequence number of the slot.
174          */
175
176         long getSequenceNumber() {
177                 return seqnum;
178         }
179
180         /**
181          * Returns the machine that sent this slot.
182          */
183
184         long getMachineID() {
185                 return machineid;
186         }
187
188         /**
189          * Records that a newer slot records the fact that this slot was
190          * sent by the relevant machine.
191          */
192
193         void setDead() {
194                 seqnumlive=false;
195                 decrementLiveCount();
196         }
197
198         /**
199          * Update the count of live entries.
200          */
201
202         void decrementLiveCount() {
203                 livecount--;
204                 if (livecount==0)
205                         table.decrementLiveCount();
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 }