--- /dev/null
+#include "Slot.h"
+#include "ByteBuffer.h"
+#include "Entry.h"
+#include "Error.h"
+#include "CloudComm.h"
+#include "Table.h"
+#include "LastMessage.h"
+#include "Mac.h"
+
+Slot::Slot(Table *_table, int64_t _seqnum, int64_t _machineid, Array<char> *_prevhmac, Array<char> *_hmac, int64_t _localSequenceNumber) :
+ seqnum(_seqnum),
+ prevhmac(_prevhmac),
+ hmac(_hmac),
+ machineid(_machineid),
+ entries(new Vector<Entry *>()),
+ livecount(1),
+ seqnumlive(true),
+ freespace(SLOT_SIZE - getBaseSize()),
+ table(_table),
+ fakeLastMessage(NULL),
+ localSequenceNumber(_localSequenceNumber) {
+}
+
+Slot::Slot(Table *_table, int64_t _seqnum, int64_t _machineid, Array<char> *_prevhmac, int64_t _localSequenceNumber) :
+ seqnum(_seqnum),
+ prevhmac(_prevhmac),
+ hmac(NULL),
+ machineid(_machineid),
+ entries(new Vector<Entry *>()),
+ livecount(1),
+ seqnumlive(true),
+ freespace(SLOT_SIZE - getBaseSize()),
+ table(_table),
+ fakeLastMessage(NULL),
+ localSequenceNumber(_localSequenceNumber) {
+}
+
+Slot::Slot(Table *_table, int64_t _seqnum, int64_t _machineid, int64_t _localSequenceNumber) :
+ seqnum(_seqnum),
+ prevhmac(new Array<char>(HMAC_SIZE)),
+ hmac(NULL),
+ machineid(_machineid),
+ entries(new Vector<Entry *>()),
+ livecount(1),
+ seqnumlive(true),
+ freespace(SLOT_SIZE - getBaseSize()),
+ table(_table),
+ fakeLastMessage(NULL),
+ localSequenceNumber(_localSequenceNumber) {
+}
+
+Slot::~Slot() {
+ if (hmac != NULL)
+ delete hmac;
+ delete prevhmac;
+ for(uint i=0; i< entries->size(); i++)
+ entries->get(i)->releaseRef();
+ delete entries;
+ if (fakeLastMessage)
+ delete fakeLastMessage;
+}
+
+Entry *Slot::addEntry(Entry *e) {
+ e = e->getCopy(this);
+ entries->add(e);
+ livecount++;
+ freespace -= e->getSize();
+ return e;
+}
+
+void Slot::addShallowEntry(Entry *e) {
+ entries->add(e);
+ livecount++;
+ freespace -= e->getSize();
+}
+
+/**
+ * Returns true if the slot has free space to hold the entry without
+ * using its reserved space. */
+
+bool Slot::hasSpace(Entry *e) {
+ int newfreespace = freespace - e->getSize();
+ return newfreespace >= 0;
+}
+
+Vector<Entry *> *Slot::getEntries() {
+ return entries;
+}
+
+Slot *Slot_decode(Table *table, Array<char> *array, Mac *mac) {
+ mac->update(array, HMAC_SIZE, array->length() - HMAC_SIZE);
+ Array<char> *realmac = mac->doFinal();
+
+ ByteBuffer *bb = ByteBuffer_wrap(array);
+ Array<char> *hmac = new Array<char>(HMAC_SIZE);
+ Array<char> *prevhmac = new Array<char>(HMAC_SIZE);
+ bb->get(hmac);
+ bb->get(prevhmac);
+ if (!realmac->equals(hmac))
+ throw new Error("Server Error: Invalid HMAC! Potential Attack!");
+ delete realmac;
+
+ int64_t seqnum = bb->getLong();
+ int64_t machineid = bb->getLong();
+ int numentries = bb->getInt();
+ Slot *slot = new Slot(table, seqnum, machineid, prevhmac, hmac, -1);
+
+ for (int i = 0; i < numentries; i++) {
+ slot->addShallowEntry(Entry_decode(slot, bb));
+ }
+ bb->releaseArray();
+ delete bb;
+ return slot;
+}
+
+char Slot::getType() {
+ return TypeSlot;
+}
+
+Array<char> *Slot::encode(Mac *mac) {
+ Array<char> *array = new Array<char>(SLOT_SIZE);
+ ByteBuffer *bb = ByteBuffer_wrap(array);
+ /* Leave space for the slot HMAC. */
+ bb->position(HMAC_SIZE);
+ bb->put(prevhmac);
+ bb->putLong(seqnum);
+ bb->putLong(machineid);
+ bb->putInt(entries->size());
+ for (uint ei = 0; ei < entries->size(); ei++) {
+ Entry *entry = entries->get(ei);
+ entry->encode(bb);
+ }
+ /* Compute our HMAC */
+ mac->update(array, HMAC_SIZE, array->length() - HMAC_SIZE);
+ Array<char> *realmac = mac->doFinal();
+ hmac = realmac;
+ bb->position(0);
+ bb->put(realmac);
+ bb->releaseArray();
+ delete bb;
+ return array;
+}
+
+
+/**
+ * Returns the live set of entries for this Slot. Generates a fake
+ * LastMessage entry to represent the information stored by the slot
+ * itself.
+ */
+
+Vector<Entry *> *Slot::getLiveEntries(bool resize) {
+ Vector<Entry *> *liveEntries = new Vector<Entry *>();
+ for (uint ei = 0; ei < entries->size(); ei++) {
+ Entry *entry = entries->get(ei);
+ if (entry->isLive()) {
+ if (!resize || entry->getType() != TypeTableStatus)
+ liveEntries->add(entry);
+ }
+ }
+
+ if (seqnumlive && !resize) {
+ if (! fakeLastMessage)
+ fakeLastMessage = new LastMessage(this, machineid, seqnum);
+ liveEntries->add(fakeLastMessage);
+ }
+ return liveEntries;
+}
+
+
+/**
+ * Records that a newer slot records the fact that this slot was
+ * sent by the relevant machine.
+ */
+
+void Slot::setDead() {
+ seqnumlive = false;
+ decrementLiveCount();
+}
+
+/**
+ * Update the count of live entries.
+ */
+
+void Slot::decrementLiveCount() {
+ livecount--;
+ if (livecount == 0) {
+ table->decrementLiveCount();
+ }
+}
+
+Array<char> *Slot::getSlotCryptIV() {
+ ByteBuffer *buffer = ByteBuffer_allocate(CloudComm_IV_SIZE);
+ buffer->putLong(machineid);
+ int64_t localSequenceNumberShift = localSequenceNumber << 16;
+ buffer->putLong(localSequenceNumberShift);
+ Array<char> * array = buffer->array();
+ buffer->releaseArray();
+ delete buffer;
+ return array;
+}