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) {
41 machineid = _machineid;
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 Entry addEntry(Entry e) {
71 freespace -= e.getSize();
75 void removeEntry(Entry e) {
78 freespace += e.getSize();
81 private void addShallowEntry(Entry e) {
84 freespace -= e.getSize();
88 * Returns true if the slot has free space to hold the entry without
89 * using its reserved space. */
91 boolean hasSpace(Entry e) {
92 int newfreespace = freespace - e.getSize();
93 return newfreespace >= 0;
96 Vector<Entry> getEntries() {
100 static Slot decode(Table table, byte[] array, Mac mac) {
101 mac.update(array, HMAC_SIZE, array.length - HMAC_SIZE);
102 byte[] realmac = mac.doFinal();
104 ByteBuffer bb = ByteBuffer.wrap(array);
105 byte[] hmac = new byte[HMAC_SIZE];
106 byte[] prevhmac = new byte[HMAC_SIZE];
109 if (!Arrays.equals(realmac, hmac))
110 throw new Error("Server Error: Invalid HMAC! Potential Attack!");
112 long seqnum = bb.getLong();
113 long machineid = bb.getLong();
114 int numentries = bb.getInt();
115 Slot slot = new Slot(table, seqnum, machineid, prevhmac, hmac);
117 for (int i = 0; i < numentries; i++) {
118 slot.addShallowEntry(Entry.decode(slot, bb));
124 byte[] encode(Mac mac) {
125 byte[] array = new byte[SLOT_SIZE];
126 ByteBuffer bb = ByteBuffer.wrap(array);
127 /* Leave space for the slot HMAC. */
128 bb.position(HMAC_SIZE);
131 bb.putLong(machineid);
132 bb.putInt(entries.size());
133 for (Entry entry : entries) {
136 /* Compute our HMAC */
137 mac.update(array, HMAC_SIZE, array.length - HMAC_SIZE);
138 byte[] realmac = mac.doFinal();
146 * Returns the empty size of a Slot. Includes 2 HMACs, the machine
147 * identifier, the sequence number, and the number of entries.
150 return 2 * HMAC_SIZE + 2 * Long.BYTES + Integer.BYTES;
154 * Returns the live set of entries for this Slot. Generates a fake
155 * LastMessage entry to represent the information stored by the slot
159 Vector<Entry> getLiveEntries(boolean resize) {
160 Vector<Entry> liveEntries = new Vector<Entry>();
161 for (Entry entry : entries) {
162 if (entry.isLive()) {
163 if (!resize || entry.getType() != Entry.TypeTableStatus)
164 liveEntries.add(entry);
168 if (seqnumlive && !resize)
169 liveEntries.add(new LastMessage(this, machineid, seqnum));
175 * Returns the sequence number of the slot.
178 long getSequenceNumber() {
183 * Returns the machine that sent this slot.
186 long getMachineID() {
191 * Records that a newer slot records the fact that this slot was
192 * sent by the relevant machine.
197 decrementLiveCount();
201 * Update the count of live entries.
204 void decrementLiveCount() {
206 if (livecount == 0) {
207 table.decrementLiveCount();
212 * Returns whether the slot stores any live information.
216 return livecount > 0;
219 public String toString() {
220 return "<" + getSequenceNumber() + ">";