2 import java.util.Vector;
3 import java.nio.ByteBuffer;
4 import javax.crypto.Mac;
5 import java.util.Arrays;
8 * Data structuring for holding Slot information.
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;
21 /** Sequence number of the slot. */
23 /** HMAC of previous slot. */
24 private byte[] prevhmac;
25 /** HMAC of this slot. */
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;
39 Slot(long _seqnum, long _machineid, byte[] _prevhmac, byte[] _hmac) {
44 entries=new Vector<Entry>();
47 freespace = SLOT_SIZE - getBaseSize();
50 Slot(long _seqnum, long _machineid, byte[] _prevhmac) {
51 this(_seqnum, _machineid, _prevhmac, null);
54 Slot(long _seqnum, long _machineid) {
55 this(_seqnum, _machineid, new byte[HMAC_SIZE], null);
62 byte[] getPrevHMAC() {
66 void addEntry(Entry e) {
69 freespace -= e.getSize();
73 * Returns true if the slot has free space to hold the entry without
74 * using its reserved space. */
76 boolean hasSpace(Entry e) {
77 int newfreespace = freespace - e.getSize();
78 return newfreespace > RESERVED_SPACE;
82 * Returns true if the slot can fit the entry potentially using the
85 boolean canFit(Entry e) {
86 int newfreespace = freespace - e.getSize();
87 return newfreespace >= 0;
90 Vector<Entry> getEntries() {
94 static Slot decode(byte[] array, Mac mac) {
95 mac.update(array, HMAC_SIZE, array.length-HMAC_SIZE);
96 byte[] realmac=mac.doFinal();
98 ByteBuffer bb=ByteBuffer.wrap(array);
99 byte[] hmac=new byte[HMAC_SIZE];
100 byte[] prevhmac=new byte[HMAC_SIZE];
103 if (!Arrays.equals(realmac, hmac))
104 throw new Error("Server Error: Invalid HMAC! Potential Attack!");
106 long seqnum=bb.getLong();
107 long machineid=bb.getLong();
108 int numentries=bb.getInt();
109 Slot slot=new Slot(seqnum, machineid, prevhmac, hmac);
111 for(int i=0; i<numentries; i++) {
112 slot.addEntry(Entry.decode(slot, bb));
118 byte[] encode(Mac mac) {
119 byte[] array=new byte[SLOT_SIZE];
120 ByteBuffer bb=ByteBuffer.wrap(array);
121 /* Leave space for the slot HMAC. */
122 bb.position(HMAC_SIZE);
125 bb.putLong(machineid);
126 bb.putInt(entries.size());
127 for(Entry entry:entries) {
130 /* Compute our HMAC */
131 mac.update(array, HMAC_SIZE, array.length-HMAC_SIZE);
132 byte[] realmac=mac.doFinal();
140 * Returns the empty size of a Slot. Includes 2 HMACs, the machine
141 * identifier, the sequence number, and the number of entries.
144 return 2*HMAC_SIZE+2*Long.BYTES+Integer.BYTES;
148 * Returns the live set of entries for this Slot. Generates a fake
149 * LastMessage entry to represent the information stored by the slot
153 Vector<Entry> getLiveEntries() {
154 Vector<Entry> liveEntries=new Vector<Entry>();
155 for(Entry entry: entries)
157 liveEntries.add(entry);
160 liveEntries.add(new LastMessage(this, machineid, seqnum));
166 * Returns the sequence number of the slot.
169 long getSequenceNumber() {
174 * Returns the machine that sent this slot.
177 long getMachineID() {
182 * Records that a newer slot records the fact that this slot was
183 * sent by the relevant machine.
187 decrementLiveCount();
192 * Update the count of live entries.
195 void decrementLiveCount() {
200 * Returns whether the slot stores any live information.
204 return livecount > 0;
207 public String toString() {
208 return "<"+getSequenceNumber()+">";