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 the size for the HMAC. */
17 static final int HMAC_SIZE=32;
19 /** Sequence number of the slot. */
21 /** HMAC of previous slot. */
22 private byte[] prevhmac;
23 /** HMAC of this slot. */
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 */
39 Slot(Table _table, long _seqnum, long _machineid, byte[] _prevhmac, byte[] _hmac) {
44 entries=new Vector<Entry>();
47 freespace = SLOT_SIZE - getBaseSize();
51 Slot(Table _table, long _seqnum, long _machineid, byte[] _prevhmac) {
52 this(_table, _seqnum, _machineid, _prevhmac, null);
55 Slot(Table _table, long _seqnum, long _machineid) {
56 this(_table, _seqnum, _machineid, new byte[HMAC_SIZE], null);
63 byte[] getPrevHMAC() {
67 void addEntry(Entry e) {
71 freespace -= e.getSize();
74 private void addShallowEntry(Entry e) {
77 freespace -= e.getSize();
81 * Returns true if the slot has free space to hold the entry without
82 * using its reserved space. */
84 boolean hasSpace(Entry e) {
85 int newfreespace = freespace - e.getSize();
86 return newfreespace >= 0;
89 Vector<Entry> getEntries() {
93 static Slot decode(Table table, byte[] array, Mac mac) {
94 mac.update(array, HMAC_SIZE, array.length-HMAC_SIZE);
95 byte[] realmac=mac.doFinal();
97 ByteBuffer bb=ByteBuffer.wrap(array);
98 byte[] hmac=new byte[HMAC_SIZE];
99 byte[] prevhmac=new byte[HMAC_SIZE];
102 if (!Arrays.equals(realmac, hmac))
103 throw new Error("Server Error: Invalid HMAC! Potential Attack!");
105 long seqnum=bb.getLong();
106 long machineid=bb.getLong();
107 int numentries=bb.getInt();
108 Slot slot=new Slot(table, seqnum, machineid, prevhmac, hmac);
110 for(int i=0; i<numentries; i++) {
111 slot.addShallowEntry(Entry.decode(slot, bb));
117 byte[] encode(Mac mac) {
118 byte[] array=new byte[SLOT_SIZE];
119 ByteBuffer bb=ByteBuffer.wrap(array);
120 /* Leave space for the slot HMAC. */
121 bb.position(HMAC_SIZE);
124 bb.putLong(machineid);
125 bb.putInt(entries.size());
126 for(Entry entry:entries) {
129 /* Compute our HMAC */
130 mac.update(array, HMAC_SIZE, array.length-HMAC_SIZE);
131 byte[] realmac=mac.doFinal();
139 * Returns the empty size of a Slot. Includes 2 HMACs, the machine
140 * identifier, the sequence number, and the number of entries.
143 return 2*HMAC_SIZE+2*Long.BYTES+Integer.BYTES;
147 * Returns the live set of entries for this Slot. Generates a fake
148 * LastMessage entry to represent the information stored by the slot
152 Vector<Entry> getLiveEntries(boolean resize) {
153 Vector<Entry> liveEntries=new Vector<Entry>();
154 for(Entry entry: entries) {
155 if (entry.isLive()) {
156 if (!resize || entry.getType() != Entry.TypeTableStatus)
157 liveEntries.add(entry);
161 if (seqnumlive && !resize)
162 liveEntries.add(new LastMessage(this, machineid, seqnum));
168 * Returns the sequence number of the slot.
171 long getSequenceNumber() {
176 * Returns the machine that sent this slot.
179 long getMachineID() {
184 * Records that a newer slot records the fact that this slot was
185 * sent by the relevant machine.
190 decrementLiveCount();
194 * Update the count of live entries.
197 void decrementLiveCount() {
200 table.decrementLiveCount();
204 * Returns whether the slot stores any live information.
208 return livecount > 0;
211 public String toString() {
212 return "<"+getSequenceNumber()+">";