From 63136ef92e46eb1ddc1b4fa945661fa20b9473fe Mon Sep 17 00:00:00 2001 From: Ali Younis Date: Wed, 21 Dec 2016 15:47:02 -0800 Subject: [PATCH] Cleaned up git --- .gitignore | 64 +- doc/iotcloud.tex | 1239 ------------- doc/makefile | 8 - doc2/iotcloud.tex | 1860 -------------------- doc2/makefile | 8 - src/java/.dir-locals.el | 2 - src/java/iotcloud/CloudComm.java | 232 --- src/java/iotcloud/Entry.java | 94 - src/java/iotcloud/IoTString.java | 105 -- src/java/iotcloud/KeyValue.java | 61 - src/java/iotcloud/LastMessage.java | 55 - src/java/iotcloud/Liveness.java | 11 - src/java/iotcloud/Makefile | 17 - src/java/iotcloud/Pair.java | 23 - src/java/iotcloud/RejectedMessage.java | 88 - src/java/iotcloud/Slot.java | 214 --- src/java/iotcloud/SlotBuffer.java | 99 -- src/java/iotcloud/SlotIndexer.java | 31 - src/java/iotcloud/Table.java | 476 ----- src/java/iotcloud/TableStatus.java | 45 - src/java/iotcloud/Test.java | 95 - src/java/iotcloud/issues.txt | 1 - src/js/iotjs/.babelrc | 1 - src/js/iotjs/.bowerrc | 3 - src/js/iotjs/.editorconfig | 13 - src/js/iotjs/.jshintrc | 18 - src/js/iotjs/README.md | 21 - src/js/iotjs/bower.json | 6 - src/js/iotjs/examples/index.html | 11 - src/js/iotjs/gulpfile.js | 49 - src/js/iotjs/orig/compat.txt | 4 - src/js/iotjs/orig/entry.js | 53 - src/js/iotjs/orig/keyvalue.js | 65 - src/js/iotjs/orig/lastmessage.js | 39 - src/js/iotjs/orig/rejectedmessage.js | 59 - src/js/iotjs/orig/slot.js | 171 -- src/js/iotjs/orig/slotbuffer.js | 89 - src/js/iotjs/orig/slotindexer.js | 27 - src/js/iotjs/orig/tablestatus.js | 34 - src/js/iotjs/package.json | 33 - src/js/iotjs/src/entry.js | 72 - src/js/iotjs/src/iotstring.js | 81 - src/js/iotjs/src/keyvalue.js | 99 -- src/js/iotjs/src/lastmessage.js | 73 - src/js/iotjs/src/liveness.js | 5 - src/js/iotjs/src/main.js | 66 - src/js/iotjs/src/pair.js | 32 - src/js/iotjs/src/rejectedmessage.js | 101 -- src/js/iotjs/src/slot.js | 208 --- src/js/iotjs/src/slotbuffer.js | 118 -- src/js/iotjs/src/slotindexer.js | 39 - src/js/iotjs/src/tablestatus.js | 66 - src/js/iotjs/test/test.js | 6 - src/script/C.cfg | 37 - src/script/java.cfg | 37 - src/script/makefile | 4 - src/server/.dir-locals.el | 2 - src/server/Makefile | 15 - src/server/README.txt | 32 - src/server/iotcloud.cpp | 40 - src/server/iotquery.cpp | 517 ------ src/server/iotquery.h | 68 - src2/java/.dir-locals.el | 2 - src2/java/iotcloud/Abort.java | 53 - src2/java/iotcloud/CloudComm.java | 235 --- src2/java/iotcloud/Commit.java | 102 -- src2/java/iotcloud/Entry.java | 116 -- src2/java/iotcloud/Guard.java | 124 -- src2/java/iotcloud/IoTString.java | 105 -- src2/java/iotcloud/KeyValue.java | 55 - src2/java/iotcloud/LastMessage.java | 55 - src2/java/iotcloud/Liveness.java | 11 - src2/java/iotcloud/Makefile | 17 - src2/java/iotcloud/NewKey.java | 57 - src2/java/iotcloud/Pair.java | 23 - src2/java/iotcloud/PendingTransaction.java | 111 -- src2/java/iotcloud/RejectedMessage.java | 88 - src2/java/iotcloud/Slot.java | 214 --- src2/java/iotcloud/SlotBuffer.java | 99 -- src2/java/iotcloud/SlotIndexer.java | 31 - src2/java/iotcloud/Table.java | 1120 ------------ src2/java/iotcloud/TableStatus.java | 45 - src2/java/iotcloud/Test.java | 75 - src2/java/iotcloud/Transaction.java | 97 - src2/java/iotcloud/issues.txt | 2 - src2/script/C.cfg | 37 - src2/script/java.cfg | 37 - src2/script/makefile | 4 - src2/server/.dir-locals.el | 2 - src2/server/Makefile | 15 - src2/server/README.txt | 32 - src2/server/iotcloud.cpp | 40 - src2/server/iotquery.cpp | 517 ------ src2/server/iotquery.h | 68 - 94 files changed, 32 insertions(+), 10799 deletions(-) delete mode 100644 doc/iotcloud.tex delete mode 100644 doc/makefile delete mode 100644 doc2/iotcloud.tex delete mode 100644 doc2/makefile delete mode 100644 src/java/.dir-locals.el delete mode 100644 src/java/iotcloud/CloudComm.java delete mode 100644 src/java/iotcloud/Entry.java delete mode 100644 src/java/iotcloud/IoTString.java delete mode 100644 src/java/iotcloud/KeyValue.java delete mode 100644 src/java/iotcloud/LastMessage.java delete mode 100644 src/java/iotcloud/Liveness.java delete mode 100644 src/java/iotcloud/Makefile delete mode 100644 src/java/iotcloud/Pair.java delete mode 100644 src/java/iotcloud/RejectedMessage.java delete mode 100644 src/java/iotcloud/Slot.java delete mode 100644 src/java/iotcloud/SlotBuffer.java delete mode 100644 src/java/iotcloud/SlotIndexer.java delete mode 100644 src/java/iotcloud/Table.java delete mode 100644 src/java/iotcloud/TableStatus.java delete mode 100644 src/java/iotcloud/Test.java delete mode 100644 src/java/iotcloud/issues.txt delete mode 100644 src/js/iotjs/.babelrc delete mode 100644 src/js/iotjs/.bowerrc delete mode 100644 src/js/iotjs/.editorconfig delete mode 100644 src/js/iotjs/.jshintrc delete mode 100644 src/js/iotjs/README.md delete mode 100644 src/js/iotjs/bower.json delete mode 100644 src/js/iotjs/examples/index.html delete mode 100644 src/js/iotjs/gulpfile.js delete mode 100644 src/js/iotjs/orig/compat.txt delete mode 100644 src/js/iotjs/orig/entry.js delete mode 100644 src/js/iotjs/orig/keyvalue.js delete mode 100644 src/js/iotjs/orig/lastmessage.js delete mode 100644 src/js/iotjs/orig/rejectedmessage.js delete mode 100644 src/js/iotjs/orig/slot.js delete mode 100644 src/js/iotjs/orig/slotbuffer.js delete mode 100644 src/js/iotjs/orig/slotindexer.js delete mode 100644 src/js/iotjs/orig/tablestatus.js delete mode 100644 src/js/iotjs/package.json delete mode 100644 src/js/iotjs/src/entry.js delete mode 100644 src/js/iotjs/src/iotstring.js delete mode 100644 src/js/iotjs/src/keyvalue.js delete mode 100644 src/js/iotjs/src/lastmessage.js delete mode 100644 src/js/iotjs/src/liveness.js delete mode 100644 src/js/iotjs/src/main.js delete mode 100644 src/js/iotjs/src/pair.js delete mode 100644 src/js/iotjs/src/rejectedmessage.js delete mode 100644 src/js/iotjs/src/slot.js delete mode 100644 src/js/iotjs/src/slotbuffer.js delete mode 100644 src/js/iotjs/src/slotindexer.js delete mode 100644 src/js/iotjs/src/tablestatus.js delete mode 100644 src/js/iotjs/test/test.js delete mode 100644 src/script/C.cfg delete mode 100644 src/script/java.cfg delete mode 100644 src/script/makefile delete mode 100644 src/server/.dir-locals.el delete mode 100644 src/server/Makefile delete mode 100644 src/server/README.txt delete mode 100644 src/server/iotcloud.cpp delete mode 100644 src/server/iotquery.cpp delete mode 100644 src/server/iotquery.h delete mode 100644 src2/java/.dir-locals.el delete mode 100644 src2/java/iotcloud/Abort.java delete mode 100644 src2/java/iotcloud/CloudComm.java delete mode 100644 src2/java/iotcloud/Commit.java delete mode 100644 src2/java/iotcloud/Entry.java delete mode 100644 src2/java/iotcloud/Guard.java delete mode 100644 src2/java/iotcloud/IoTString.java delete mode 100644 src2/java/iotcloud/KeyValue.java delete mode 100644 src2/java/iotcloud/LastMessage.java delete mode 100644 src2/java/iotcloud/Liveness.java delete mode 100644 src2/java/iotcloud/Makefile delete mode 100644 src2/java/iotcloud/NewKey.java delete mode 100644 src2/java/iotcloud/Pair.java delete mode 100644 src2/java/iotcloud/PendingTransaction.java delete mode 100644 src2/java/iotcloud/RejectedMessage.java delete mode 100644 src2/java/iotcloud/Slot.java delete mode 100644 src2/java/iotcloud/SlotBuffer.java delete mode 100644 src2/java/iotcloud/SlotIndexer.java delete mode 100644 src2/java/iotcloud/Table.java delete mode 100644 src2/java/iotcloud/TableStatus.java delete mode 100644 src2/java/iotcloud/Test.java delete mode 100644 src2/java/iotcloud/Transaction.java delete mode 100644 src2/java/iotcloud/issues.txt delete mode 100644 src2/script/C.cfg delete mode 100644 src2/script/java.cfg delete mode 100644 src2/script/makefile delete mode 100644 src2/server/.dir-locals.el delete mode 100644 src2/server/Makefile delete mode 100644 src2/server/README.txt delete mode 100644 src2/server/iotcloud.cpp delete mode 100644 src2/server/iotquery.cpp delete mode 100644 src2/server/iotquery.h diff --git a/.gitignore b/.gitignore index 8e8a718..ff6f60c 100644 --- a/.gitignore +++ b/.gitignore @@ -16,36 +16,36 @@ test/bower_components .DS_Store # Joel Bandi says : Some tex dependencies i had to locally download ..please ignore this -doc/README -doc/algc.sty -doc/algcompatible.sty -doc/algmatlab.sty -doc/algorithmicx.pdf -doc/algorithmicx.sty -doc/algorithmicx.tex -doc/algpascal.sty -doc/algpseudocode.sty -doc/iotcloud.aux -doc/iotcloud.log -doc/iotcloud.pdf -doc2/README -doc2/algc.sty -doc2/algcompatible.sty -doc2/algmatlab.sty -doc2/algorithmicx.pdf -doc2/algorithmicx.sty -doc2/algorithmicx.tex -doc2/algpascal.sty -doc2/algpseudocode.sty -doc2/iotcloud.aux -doc2/iotcloud.log -doc2/iotcloud.pdf -version2/doc/iotcloud_formal/iotcloud.aux -version2/doc/iotcloud_formal/iotcloud.log -version2/doc/iotcloud_formal/iotcloud.pdf -version2/doc/iotcloud_formal/iotcloud.out -version2/doc/iotcloud_informal/iotcloud.aux -version2/doc/iotcloud_informal/iotcloud.log -version2/doc/iotcloud_informal/iotcloud.pdf -version2/doc/iotcloud_informal/iotcloud.out +version1/doc/README +version1/doc/algc.sty +version1/doc/algcompatible.sty +version1/doc/algmatlab.sty +version1/doc/algorithmicx.pdf +version1/doc/algorithmicx.sty +version1/doc/algorithmicx.tex +version1/doc/algpascal.sty +version1/doc/algpseudocode.sty +version1/doc/iotcloud.aux +version1/doc/iotcloud.log +version1/doc/iotcloud.pdf +version2/doc/README +version2/doc/algc.sty +version2/doc/algcompatible.sty +version2/doc/algmatlab.sty +version2/doc/algorithmicx.pdf +version2/doc/algorithmicx.sty +version2/doc/algorithmicx.tex +version2/doc/algpascal.sty +version2/doc/algpseudocode.sty +version2/doc/iotcloud.aux +version2/doc/iotcloud.log +version2/doc/iotcloud.pdf +non_block_chain/doc/iotcloud_formal/iotcloud.aux +non_block_chain/doc/iotcloud_formal/iotcloud.log +non_block_chain/doc/iotcloud_formal/iotcloud.pdf +non_block_chain/doc/iotcloud_formal/iotcloud.out +non_block_chain/doc/iotcloud_informal/iotcloud.aux +non_block_chain/doc/iotcloud_informal/iotcloud.log +non_block_chain/doc/iotcloud_informal/iotcloud.pdf +non_block_chain/doc/iotcloud_informal/iotcloud.out diff --git a/doc/iotcloud.tex b/doc/iotcloud.tex deleted file mode 100644 index 9d10557..0000000 --- a/doc/iotcloud.tex +++ /dev/null @@ -1,1239 +0,0 @@ -\documentclass[11pt]{article} -\newcommand{\tuple}[1]{\ensuremath \langle #1 \rangle} -\usepackage{color} -\usepackage{amsthm} -\usepackage{amsmath} -\usepackage{graphicx} -\usepackage{mathrsfs} -\usepackage{algpseudocode}% http://ctan.org/pkg/algorithmicx -\usepackage[all]{xy} -\newtheorem{theorem}{Theorem} -\newtheorem{prop}{Proposition} -\newtheorem{lem}{Lemma} -\newtheorem{defn}{Definition} -\newcommand{\note}[1]{{\color{red} \bf [[#1]]}} -\newcommand{\push}[1][1]{\hskip\dimexpr #1\algorithmicindent\relax} -\begin{document} -\section{Approach} - -\subsection{Keys} - -Each device has: user id + password - -Server login is: -hash1(user id), hash1(password) - -Symmetric Crypto keys is: -hash2(user id | password) - -Server has finite length queue of entries + max\_entry\_identifier + -server login key - -\subsection{Entry layout} -Each entry has: -\begin{enumerate} -\item Sequence identifier -\item Random IV (if needed by crypto algorithm) -\item Encrypted payload -\end{enumerate} - -Payload has: -\begin{enumerate} -\item Sequence identifier -\item Machine id (most probably something like a 64-bit random number -that is self-generated by client) -\item HMAC of previous slot -\item Data entries -\item HMAC of current slot -\end{enumerate} - -A data entry can be one of these: -\begin{enumerate} -\item All or part of a Key-value entry -\item Slot sequence entry: Machine id + last message identifier -\newline {The purpose of this is to keep the record of the last slot -from a certain client if a client's update has to expunge that other -client's last entry from the queue. This is kept in the slot until -the entry owner inserts a newer update into the queue.} -\item Queue state entry: Includes queue size \newline {The purpose -of this is for the client to tell if the server lies about the number -of slots in the queue, e.g. if there are 2 queue state entry in the queue, -e.g. 50 and 70, the client knows that when it sees 50, it should expect -at most 50 slots in the queue and after it sees 70, it should expect -50 slots before that queue state entry slot 50 and at most 70 slots. -The queue state entry slot 70 is counted as slot number 51 in the queue.} -\item Collision resolution entry: message identifier + machine id of a -collision winner -\newline {The purpose of this is to keep keep track of the winner of -all the collisions until all clients have seen the particular entry.} -\end{enumerate} - -\subsection{Live status} - -Live status of entries: -\begin{enumerate} -\item Key-Value Entry is dead if either (a) there is a newer key-value pair or (b) it is incomplete. - -\item Slot sequence number (of either a message version data -or user-level data) is dead if there is a newer slot from the same machine. - -\item Queue state entry is dead if there is a newer queue state entry. -{In the case of queue state entries 50 and 70, this means that queue state -entry 50 is dead and 70 is live. However, not until the number of slots reaches -70 that queue state entry 50 will be expunged from the queue.} - -\item Collision resolution entry is dead if this entry has been seen -by all clients after a collision happens. -\end{enumerate} - -When data is at the end of the queue ready to expunge, if: -\begin{enumerate} -\item The key-value entry is not dead, it must be reinserted at the -beginning of the queue. - -\item If the slot sequence number is not dead, then a message sequence -entry must be inserted. - -\item If the queue state entry is not dead, it must be reinserted at the -beginning of the queue. -\end{enumerate} - - -\paragraph{Reads:} -Client sends a sequence number. Server replies with either: all data -entries or all newer data entries. - -\paragraph{Writes:} -Client sends slot, server verifies that sequence number is valid, -checks entry hash, and replies with an accept message if all checks -pass. On success, client updates its sequence number. On failure, -server sends updates slots to client and client validates those slots. - -\paragraph{Local state on each client:} -A list of machines and the corresponding latest sequence numbers. - -\paragraph{Validation procedure on client:} -\begin{enumerate} -\item Decrypt each new slot in order. -\item For each slot: - (a) check its HMAC, and - (b) check that the previous entry HMAC field matches the previous - entry. -\item Check that the last-message entry for our machine matches the stored HMAC of our last message sent. -\item For all other machines, check that the latest sequence number is -at least as large (never goes backwards). -\item That the queue has a current queue state entry. -\item That the number of entries received is consistent with the size -specified in the queue state entry. -\end{enumerate} - -Key-value entries can span multiple slots. They aren't valid until -they are complete. - -\subsection{Resizing Queue} -Client can make a request to resize the queue. This is done as a write that combines: - (a) a slot with the message, and (b) a request to the server. The queue can only be expanded, never contracted; attempting to decrease the size of the queue will cause future clients to throw an error. - -\subsection{Server Algorithm} -$s \in SN$ is a sequence number\\ -$sv \in SV$ is a slot's value\\ -$slot_s = \tuple{s, sv} \in SL \subseteq SN \times SV$ \\ \\ -\textbf{State} \\ -\textit{SL = set of live slots on server} \\ -\textit{max = maximum number of slots (input only for resize message)} \\ -\textit{n = number of slots} \\ \\ -\textbf{Helper Function} \\ -$MaxSlot(SL_s)= \tuple{s, sv} \mid \tuple{s, sv} -\in SL_s \wedge \forall \tuple{s_s, sv_s} \in SL_s, s \geq s_s$ \\ -$MinSlot(SL_s)= \tuple{s, sv} \mid \tuple{s, sv} -\in SL_s \wedge \forall \tuple{s_s, sv_s} \in SL_s, s \leq s_s$ \\ -$SeqN(slot_s = \tuple{s, sv})=s$ \\ -$SlotVal(slot_s = \tuple{s, sv})=sv$ \\ - -\begin{algorithmic}[1] -\Function{GetSlot}{$s_g$} -\State \Return{$\{\tuple{s, sv} \in SL \mid s \geq s_g\}$} -\EndFunction -\end{algorithmic} - -\begin{algorithmic}[1] -\Function{PutSlot}{$s_p,sv_p,max'$} -\If{$(max' \neq \emptyset)$} \Comment{Resize} -\State $max \gets max'$ -\EndIf -\State $\tuple{s_n,sv_n} \gets MaxSlot(SL)$\Comment{Last sv} -%\State $s_n \gets SeqN(\tuple{s_n,sv_n})$ -\If{$(s_p = s_n + 1)$} - \If{$n = max$} - \State $\tuple{s_m,sv_m} \gets MinSlot(SL)$\Comment{First sv} - \State $SL \gets SL - \{\tuple{s_m,sv_m}\}$ - \Else \Comment{$n < max$} - \State $n \gets n + 1$ - \EndIf - \State $SL \gets SL \cup \{\tuple{s_p,sv_p}\}$ - \State \Return{$(true,\emptyset)$} -\Else - \State \Return{$(false,\{\tuple{s,sv}\in SL \mid - s \geq s_p\})$} -\EndIf -\EndFunction -\end{algorithmic} - -\subsection{Client Algorithm} -\subsubsection{Reading Slots} -\textbf{Data Entry} \\ -$k$ is key of entry \\ -$v$ is value of entry \\ -$kv$ is a key-value entry $\tuple{k,v}$, $kv \in DE$ \\ -$ss$ is a slot sequence entry $\tuple{id,s_{last}}$, -id + last s of a machine, $ss \in DE$ \\ -$qs$ is a queue state entry (contains $max$ size of queue), $qs \in DE$ \\ -$cr$ is a collision resolution entry $\tuple{s_{col},id_{col}}$, -s + id of a machine that wins a collision, $cr \in DE$ \\ -$de$ is a data entry that can be a $kv$, $ss$, $qs$, or $cr$ \\ -$DE$ is a set of all data entries, possibly of different types, in a single message \\ -$s \in SN$ is a sequence number \\ -$id$ is a machine ID\\ -$hmac_p$ is the HMAC value of the previous slot \\ -$hmac_c$ is the HMAC value of the current slot \\ -$hmac_{p_g}$ is the HMAC value of the previous slot in procedure $\Call{ProcessSL}{}$ \\ -$hmac_{c_g}$ is the HMAC value of the current slot in procedure $\Call{ProcessSL}{}$ \\ -$Dat_s = \tuple{s,id,hmac_p,DE,hmac_c}$ \\ -$slot_s = \tuple{s, E(Dat_s)} = -\tuple{s, E(\tuple{s,id,hmac_p,DE,hmac_c})}$ \\ \\ -\textbf{States} \\ -\textit{$d$ = delta between the last $s$ recorded and the first $s$ received} \\ -\textit{$id_{self}$ = machine Id of this client} \\ -\textit{$max_g$ = maximum number of slots (initially $max_g > 0$)} \\ -\textit{$sl_{last}$ = info of last slot in queue = - $\tuple{s_{last},sv_{last},id_{last}}$ (initially $\emptyset$)} \\ -\textit{DT = set of $\tuple{k,v}$ on client} \\ -\textit{MS = associative array of $\tuple{id, s_{last}}$ of all clients on client -(initially empty)} \\ -\textit{$LV$ = live set of $kv$ entries on client, contains - $\tuple{kv,s}$ entries} \\ -\textit{$SS_{live}$ = live set of $ss$ entries on client} \\ -\textit{$CR_{live}$ = live set of $cr$ entries on client} \\ -\textit{$MS_g$ = set MS to save all $\tuple{id, s_{last}}$ pairs while -traversing DT after a request to server (initially empty)} \\ -\textit{SK = Secret Key} \\ -\textit{$SM$ = associative array of $\tuple{s, id}$ of all slots in previous reads -(initially empty)} \\ \\ -\textbf{Helper Functions} \\ -$MaxSlot(SL_s)= \tuple{s, sv}$ \textit{such that} $\tuple{s, sv} - \in SL_s \wedge \forall \tuple{s_s, sv_s} \in SL_s, s \geq s_s$ \\ -$MinSlot(SL_s)= \tuple{s, sv}$ \textit{such that} $\tuple{s, sv} - \in SL_s \wedge \forall \tuple{s_s, sv_s} \in SL_s, s \leq s_s$ \\ -$Slot(SL_s,s_s)= \tuple{s, sv}$ \textit{such that} $\tuple{s, sv} - \in SL_s \wedge \forall \tuple{s_s, sv_s} \in SL_s, s = s_s$ \\ -$SeqN(\tuple{s, sv})=s$ \\ -$SlotVal(\tuple{s, sv})=sv$ \\ -$CreateLastSL(s,sv,id)=\tuple{s,sv,id}=sl_{last}$ \\ -$Decrypt(SK_s,sv_s)=Dat_s=\tuple{s,id,hmac_p,DE,hmac_c}$ \\ -$GetSeqN(Dat_s = \tuple{s,id,hmac_p,DE,hmac_c})=s$ \\ -$GetMacId(Dat_s = \tuple{s,id,hmac_p,DE,hmac_c})=id$ \\ -$GetPrevHmac(Dat_s = \tuple{s,id,hmac_p,DE,hmac_c})=hmac_p$ \\ -$GetCurrHmac(Dat_s = \tuple{s,id,hmac_p,DE,hmac_c})=hmac_c$ \\ -$GetDatEnt(Dat_s = \tuple{s,id,hmac_p,DE,hmac_c})=DE$ \\ -$GetLiveSS(SS_{live},ss_s)= ss$ \textit{such that} $ss \in SS_{live} - \wedge \forall ss_s \in SS_{live}, ss = ss_s$ \\ -$GetLiveCR(CR_{live},cr_s)= cr$ \textit{such that} $cr \in CR_{live} - \wedge \forall cr_s \in CR_{live}, cr = cr_s$ \\ -$GetLivEntLastS(LV_s,kv_s)= s$ \textit{such that} $\tuple{kv, s} \in LV_s - \wedge \forall \tuple{kv_s, s_s} \in LV_s, kv_s = kv$ \\ -$GetKV($key-value data entry$)=\tuple{k_s,v_s} = kv_s$ \\ -$GetSS($slot-sequence data entry$)=\tuple{id_s,s_{s_{last}}} = ss_s$ \\ -$GetCR($de$)=\tuple{s_s,id_s} = cr_s$ \\ -$Hmac(Dat_s,SK) = hmac_c$ \textit{value computed from $s$, $id$, -$hmac_p$, and $DE$ taken from $Dat_s$} \\ -$IsKv(de) = true$ \textit{if $de$ is a $kv$, false otherwise} \\ -$IsSs(de) = true$ \textit{if $de$ is a $ss$, false otherwise} \\ -$IsQs(de) = true$ \textit{if $de$ is a $qs$, false otherwise} \\ -$IsCr(de) = true$ \textit{if $de$ is a $cr$, false otherwise} \\ -$GetKey(kv)=k$\Comment{$kv = \tuple{k, v}$} \\ -$GetVal(kv)=v$ \\ -$GetId(ss)=id$\Comment{$ss = \tuple{id, s_{last}}$} \\ -$GetSLast(ss)=s_{last}$ \\ -$GetS(cr)=s$\Comment{$cr = \tuple{s, id}$} \\ -$GetId(cr)=id$ \\ -$GetLastS(sl_{last})=s$\Comment{$sl_{last} = \tuple{s,sv,id}$} \\ -$GetSV(sl_{last})=sv$ \\ -$GetID(sl_{last})=id$ \\ -$GetKeyVal(DT_s,k_s)= \tuple{k, v}$ \textit{such that} $\tuple{k, v} - \in DT_s \wedge \forall \tuple{k_s, v_s} \in DT_s, k = k_s$ \\ -$MaxLastSeqN(MS_s)= s_{last}$ \textit{such that} $\tuple{id, s_{last}} \in MS_s - \wedge \forall \tuple{id_s, s_{s_{last}}} \in MS_s, s_{last} \geq s_{s_{last}}$ \\ -$MinLastSeqN(MS_s)= s_{last}$ \textit{such that} $\tuple{id, s_{last}} \in MS_s - \wedge \forall \tuple{id_s, s_{s_{last}}} \in MS_s, s_{last} \leq s_{s_{last}}$ \\ -$MinCRSeqN(CR_s)= s$ \textit{such that} $\tuple{s, id} \in CR_s - \wedge \forall \tuple{s_s, id_s} \in CR_s, s \leq s_s$ \\ -$MaxSMSeqN(SM_s)= s$ \textit{such that} $\tuple{s, id} \in SM_s - \wedge \forall \tuple{s_s, id_s} \in SM_s, s \geq s_s$ \\ - -\begin{algorithmic}[1] -\Procedure{Error}{$msg$} -\State $Print(msg)$ -\State $Halt()$ -\EndProcedure -\end{algorithmic} - -\begin{algorithmic}[1] -\Function{GetQueSta}{$DE_s$} -\State $qs_{de} \gets qs$ \textit{such that} $qs \in DE_s, - de_s \in D \land IsQs(de_s)$ -\If{$qs_{de} \neq \emptyset$} - \State $qs_{ret} \gets qs_{de})$ -\Else - \State $qs_{ret} \gets \emptyset$ -\EndIf -\State \Return{$qs_{ret}$} -\EndFunction -\end{algorithmic} - -\begin{algorithmic}[1] -\Function{GetSlotSeq}{$DE_s$} -\State $DE_{ss} \gets \{de | de \in DE_s \land IsSs(de)\}$ -\State \Return{$DE_{ss}$} -\EndFunction -\end{algorithmic} - -\begin{algorithmic}[1] -\Function{GetColRes}{$DE_s$} -\State $DE_{cr} \gets \{de | de \in DE_s \land IsCr(de)\}$ -\State \Return{$DE_{cr}$} -\EndFunction -\end{algorithmic} - -\begin{algorithmic}[1] -\Function{UpdateLastSeqN}{$id_s,s_s,MS_s$} -\State $s_t \gets MS_s[id_s]$ -\If{$s_t = \emptyset$} - \State $MS_s[id_s] = s_s$ \Comment{First occurrence} -\Else - \If{$id_s = id_{self}$} - \If{$s_t \neq s_s$}\Comment{Check for mismatch on $s$} - \State \Call{Error}{'Mismatch on $s$ for $id_{self}$'} - \EndIf - \Else - \If{$s_t > s_s$}\Comment{Check for rollback on $s$} - \State \Call{Error}{'Rollback on $s$ for $id_s$'} - \EndIf - \EndIf - \State $MS_S[id_s] \gets max(s_t, s_s)$ -\EndIf -\State \Return{$MS_s$} -\EndFunction -\end{algorithmic} - -\begin{algorithmic}[1] -\Function{UpdateKVLivEnt}{$LV_s,kv_s,s_s$} -\State $s_t \gets GetLivEntLastS(LV_s,kv_s)$ -\If{$s_t = \emptyset$} - \State $LV_s \gets LV_s \cup \{\tuple{kv_s,s_s}\}$\Comment{First occurrence} -\Else - \If{$s_s > s_t$}\Comment{Update entry with a later s} - \State $LV_s \gets (LV_s - \{\tuple{kv_s,s_t}\}) \cup - \{\tuple{kv_s,s_s}\}$ - \EndIf -\EndIf -\State \Return{$LV_s$} -\EndFunction -\end{algorithmic} - -\begin{algorithmic}[1] -\Function{AddSSLivEnt}{$SS_{s_{live}},de_s$} -\State $ss_s \gets GetSS(de_s)$ -\State $ss_t \gets GetLiveSS(SS_{s_{live}},ss_s)$ -\If{$ss_t = \emptyset$} - \State $SS_{s_{live}} \gets SS_{s_{live}} \cup \{ss_s\}$\Comment{First occurrence} -\EndIf -\State \Return{$SS_{s_{live}}$} -\EndFunction -\end{algorithmic} - -\begin{algorithmic}[1] -\Function{AddCRLivEnt}{$CR_{s_{live}},cr_s$} -\State $cr_t \gets GetLiveCR(CR_{s_{live}},cr_s)$ -\If{$cr_t = \emptyset$} - \State $CR_{s_{live}} \gets CR_{s_{live}} \cup \{cr_s\}$\Comment{First occurrence} -\EndIf -\State \Return{$CR_{s_{live}}$} -\EndFunction -\end{algorithmic} - -\begin{algorithmic}[1] -\Function{UpdateSSLivEnt}{$SS_{s_{live}},MS_s$} -\State $s_{s_{min}} \gets MinLastSeqN(MS_s)$ -\ForAll{$ss_s \in SS_{s_{live}}$} - \State $s_{s_{last}} \gets GetSLast(ss_s)$ - \If{$s_{s_{min}} > s_{s_{last}}$}\Comment{Remove if dead} - \State $SS_{s_{live}} \gets SS_{s_{live}} - \{ss_s\}$ - \EndIf -\EndFor -\State \Return{$SS_{s_{live}}$} -\EndFunction -\end{algorithmic} - -\begin{algorithmic}[1] -\Function{UpdateCRLivEnt}{$CR_{s_{live}},MS_s$} -\State $s_{s_{min}} \gets MinLastSeqN(MS_s)$ -\ForAll{$cr_s \in CR_{s_{live}}$} - \State $s_s \gets GetS(cr_s)$ - \If{$s_{s_{min}} > s_s$}\Comment{Remove if dead} - \State $CR_{s_{live}} \gets CR_{s_{live}} - \{cr_s\}$ - \EndIf -\EndFor -\State \Return{$CR_{s_{live}}$} -\EndFunction -\end{algorithmic} - -\begin{algorithmic}[1] -\Function{UpdateSM}{$SM_s,CR_s$}\Comment{Remove if dead} -\State $s_{cr_{min}} \gets MinCRSeqN(CR_s)$ - \State $SM_s \gets SM_s - \{\tuple{s_s,id_s} \mid \tuple{s_s,id_s} - \in SM_s \wedge s_s < s_{cr_{min}}\}$ -\State \Return{$CR_{s_{live}}$} -\EndFunction -\end{algorithmic} - -\begin{algorithmic}[1] -\Procedure{CheckLastSeqN}{$MS_s,MS_t,d$} -\For {$\tuple{id, s_t}$ in $MS_t$}\Comment{Check $MS_t$ based on the newer $MS_s$} - \State $s_s \gets MS_s[id]$ - \If{$d \land s_s = \emptyset$} - \State \Call{Error}{'Missing $s$ for machine $id$'} - \ElsIf{$id = id_{self}$ and $s_s \neq s_t$} - \State \Call{Error}{'Invalid last $s$ for this machine'} - \ElsIf{$id \neq id_{self}$ and $s_{s_{last}} < s_{t_{last}}$} - \State \Call{Error}{'Invalid last $s$ for machine $id$'} - \Else - \State $MS_t[id] \gets s_s$ - \EndIf -\EndFor -\EndProcedure -\end{algorithmic} - -\begin{algorithmic}[1] -\Procedure{CheckCollision}{$MS_s,SM_s,cr_s$} -\If{$cr_s \neq \emptyset$} - \State $s_s \gets GetS(cr_s)$ - \State $id_s \gets GetId(cr_s)$ - \State $s_{s_{last}} \gets GetLastSeqN(MS_s,id_s)$ - \If{$s_{s_{last}} < s_s$} - \State $id_t \gets SM_s[s_s]$ - \If{$id_s \neq id_t$} - \State \Call{Error}{'Invalid $id$ for this slot update'} - \EndIf - \EndIf -\EndIf -\EndProcedure -\end{algorithmic} - -\begin{algorithmic}[1] -\Function{ValidSlotsRange}{$s_{s_{min}}$} -\State $s_{s_{last}} \gets MaxSMSeqN(SM)$ -\If{$s_{s_{min}} \leq s_{s_{last}}$} - \State \Call{Error}{'Server sent old slots'} -\EndIf -\State \Return{$s_{s_{min}} > s_{s_{last}} + 1$} -\EndFunction -\end{algorithmic} - -\begin{algorithmic}[1] -\Procedure{CheckNumSlots}{$|SL_s|,sz_s$} -\If{$|SL_s| \neq sz_s$} - \State \Call{Error}{'Actual number of slots does not match expected'} -\EndIf -\EndProcedure -\end{algorithmic} - -\begin{algorithmic}[1] -\Function{StoreLastSlot}{$MS_s,sl_l,s_s,sv_s,id_s$} -\State $s_{min} \gets MinLastSeqN(MS_s)$ -\If{$s_{min} \neq \emptyset \land s_{min} = s_s$}\Comment{$MS$ initially empty} - \State $sl_l \gets CreateLastSL(s_s,sv_s,id_s)$ -\EndIf -\State \Return{$sl_l$} -\EndFunction -\end{algorithmic} - -\begin{algorithmic}[1] -\Function{ValidHmacChain}{$Dat_s,s_s,hmac_{p_s},sl_l$} - \State $hmac_{p_{stored}} \gets GetPrevHmac(Dat_s)$ - \If {$ \neg(s_s = 0 \land hmac_{p_s} = 0)$} - \State $s_l \gets GetLastS(sl_l)$ - \If {$(s_s > s_l + 1) \land (hmac_{p_{stored}} \neq hmac_{p_s})$} - \State \Call{Error}{'Invalid previous HMAC value'} - \EndIf - \EndIf - \If{$Hmac(Dat_s,SK) \neq GetCurrHmac(Dat_s)$ } - \State \Call{Error}{'Invalid current HMAC value'} - \EndIf - \State $hmac_{p_s} \gets Hmac(Dat_s,SK)$\Comment{Update $hmac_{p_s}$ for next check} -\State \Return{$hmac_{p_s}$} -\EndFunction -\end{algorithmic} - -\begin{algorithmic}[1] -\Function{UpdateDT}{$DT_s,DE_s,LV_s,s_s$} -\State $DE_{s_{kv}} \gets \{de_s | de_s \in DE_s \land IsKv(de_s)\}$ -\ForAll{$de_s \in DE_{s_{kv}}$} - \State $kv_s \gets GetKV(de_s)$ - \State $LV_s \gets \Call{UpdateKVLivEnt}{LV_s,kv_s,s_s}$ - \State $k_s \gets GetKey(kv_s)$ - \State $\tuple{k_s,v_t} \gets GetKeyVal(DT_s,k_s)$ - \If{$\tuple{k_s,v_t} = \emptyset$} - \State $DT_s \gets DT_s \cup \{\tuple{k_s,v_s}\}$ - \Else - \State $DT_s \gets (DT_s - \{\tuple{k_s,v_t}\}) \cup - \{\tuple{k_s,v_s}\}$ - \EndIf -\EndFor -\State \Return{$DT_s$} -\EndFunction -\end{algorithmic} - -\begin{algorithmic}[1] -\Function{InitExpSize}{$s_{min}$} -\If{$s_{min} < max_g$}\Comment{Check whether $SL$ is full on server} - \State $sz_s \gets s_{min}$ -\Else - \State $sz_s \gets max_g$ -\EndIf -\State \Return{$sz_s$} -\EndFunction -\end{algorithmic} - -\begin{algorithmic}[1] -\Function{UpdateExpSize}{$sz_s$} -\State $sz_s \gets sz_s + 1$ -\If{$sz_s > max_g$}\Comment{Expected size $\leq max_g$} - \State $sz_s \gets max_g$ -\EndIf -\State \Return{$sz_s$} -\EndFunction -\end{algorithmic} - -\begin{algorithmic}[1] -\Function{UpdateQS}{$Dat_s,max_s$} -\State $DE_s \gets GetDatEnt(Dat_s)$ -\State $qs_s \gets \Call{GetQueSta}{DE_s}$\Comment{Handle qs} -\If{$qs_s \neq \emptyset \land qs_s > max_s$} - \State $max_s \gets qs_s$ -\EndIf -\State \Return{$max_s$} -\EndFunction -\end{algorithmic} - -\begin{algorithmic}[1] -\Procedure{UpdateCR}{$DE_s$} -\State $DE_{s_{cr}} \gets \Call{GetColRes}{DE_s}$\Comment{Handle cr} -\If{$DE_{s_{cr}} \neq \emptyset$} - \ForAll{$de_{s_{cr}} \in DE_{s_{cr}}$} - \State $cr_s \gets GetCR(de_{s_{cr}})$ - \State $\Call{CheckCollision}{MS,SM,cr_s}$ - \State $CR_{live} \gets \Call{AddCRLivEnt}{CR_{live},cr_s}$ - \EndFor -\EndIf -\EndProcedure -\end{algorithmic} - -\begin{algorithmic}[1] -\Function{UpdateSS}{$DE_s,MS_s$} -\State $DE_{s_{ss}} \gets \Call{GetSlotSeq}{DE_s}$\Comment{Handle ss} -\If{$DE_{s_{ss}} \neq \emptyset$} - \ForAll{$de_{s_{ss}} \in DE_{s_{ss}}$} - \State $\tuple{id_d,s_{d_{last}}} \gets GetSS(de_{s_{ss}})$ - \State $MS_s \gets \Call{UpdateLastSeqN}{id_d,s_{d_{last}},MS_s}$ - \State $SS_{live} \gets \Call{AddSSLivEnt}{SS_{live},de_{s_{ss}}}$ - \EndFor -\EndIf -\State \Return{$MS_s$} -\EndFunction -\end{algorithmic} - -\begin{algorithmic}[1] -\Procedure{ProcessSL}{$SL_g$} -\State $MS_g \gets \emptyset$ -\State $\tuple{s_{g_{min}},sv_{g_{min}}} \gets MinSlot(SL_g)$ -\State $\tuple{s_{g_{max}},sv_{g_{max}}} \gets MaxSlot(SL_g)$ -\State $d \gets \Call{ValidSlotsRange}{s_{g_{min}}}$ -\State $sz \gets \Call{InitExpSize}{s_{g_{min}}}$ -\For{$s_g \gets s_{g_{min}}$ \textbf{to} $s_{g_{max}}$}\Comment{Process slots - in $SL_g$ in order} - \State $\tuple{s_g,sv_g} \gets Slot(SL_g,s_g)$ - \State $Dat_g \gets Decrypt(SK,sv_g)$ - \State $id_g \gets GetMacId(Dat_g)$ - \State $SM \gets SM \cup \{\tuple{s_g,id_g}\}$ - \State $s_{g_{in}} \gets GetSeqN(Dat_g)$ - \If{$s_g \neq s_{g_{in}}$} - \State \Call{Error}{'Invalid sequence number'} - \EndIf - \State $hmac_{p_g} \gets \Call{ValidHmacChain}{Dat_g,s_g,hmac_{p_g},sl_{last}}$ - \State $sz \gets \Call{UpdateExpSize}{sz}$ - \State $max_g \gets \Call{UpdateQS}{Dat_g,max_g}$\Comment{Handle qs} - \State $MS_g \gets \Call{UpdateLastSeqN}{id_g,s_g,MS_g}$\Comment{Handle last s} - \State $MS_g \gets \Call{UpdateSS}{DE_g,MS_g}$\Comment{Handle ss} - %\State $DE_{g_{ss}} \gets \Call{GetSlotSeq}{DE_g}$\Comment{Handle ss} - %\If{$DE_{g_{ss}} \neq \emptyset$} - % \ForAll{$de_{g_{ss}} \in DE_{g_{ss}}$} - % \State $\tuple{id_d,s_{d_{last}}} \gets GetSS(de_{g_{ss}})$ - % \State $MS_g \gets \Call{UpdateLastSeqN}{id_d,s_{d_{last}},MS_g}$ - % \State $SS_{live} \gets \Call{AddSSLivEnt}{SS_{live},de_{g_{ss}}}$ - % \EndFor - %\EndIf - \State $\Call{UpdateCR}{DE_g}$\Comment{Handle cr} - %\State $DE_{g_{cr}} \gets \Call{GetColRes}{DE_g}$\Comment{Handle cr} - %\If{$DE_{g_{cr}} \neq \emptyset$} - % \ForAll{$de_{g_{cr}} \in DE_{g_{cr}}$} - % \State $cr_g \gets GetCR(de_{g_{cr}})$ - % \State $\Call{CheckCollision}{MS,SM,cr_g}$ - % \State $CR_{live} \gets \Call{AddCRLivEnt}{CR_{live},cr_g}$ - % \EndFor - %\EndIf - \State $sl_{last} \gets \Call{StoreLastSlot}{MS,sl_{last},s_g,sv_g,id_g}$ - \State $DT \gets \Call{UpdateDT}{DT,DE_g,LV,s_g}$ -\EndFor -\State $\Call{CheckLastSeqN}{MS_g,MS,d}$ -\State $\Call{CheckNumSlots}{|SL_g|,sz}$ -\State $\Call{UpdateSSLivEnt}{SS_{live},MS}$ -\State $\Call{UpdateCRLivEnt}{CR_{live},MS}$ -\State $\Call{UpdateSM}{SM,CR_{live}}$ -\EndProcedure -\end{algorithmic} - -\begin{algorithmic}[1] -\Procedure{GetKVPairs}{} -\State $s_g \gets GetLastSeqN(MS,id_{self}) + 1$ -\State $SL_c \gets \Call{GetSlot}{s_g}$ -\State $\Call{ProcessSL}{SL_c}$\Comment{Process slots and update DT} -\EndProcedure -\end{algorithmic} - -\begin{algorithmic}[1] -\Function{Get}{$k_g$} \Comment{Interface function to get a value} -\State $\tuple{k_s,v_s} \gets \tuple{k,v}$ \textit{such that} $\tuple{k,v} - \in DT \land k = k_g$ -\State \Return{$v_s$} -\EndFunction -\end{algorithmic} - -\subsubsection{Writing Slots} -\textbf{States} \\ -\textit{$cp$ = data entry $DE$ maximum size/capacity} \\ -\textit{$ck_p$ = counter of $kv \in KV$ for putting pairs (initially 0)} \\ -\textit{$ck_g$ = counter of $kv \in KV$ for getting pairs (initially 0)} \\ -\textit{$cs_p$ = counter of $ss \in SS$ for putting pairs (initially 0)} \\ -\textit{$cs_g$ = counter of $ss \in SS$ for getting pairs (initially 0)} \\ -\textit{$cc_p$ = counter of $cr \in CR$ for putting pairs (initially 0)} \\ -\textit{$cc_g$ = counter of $cr \in CR$ for getting pairs (initially 0)} \\ -\textit{$hmac_{c_p}$ = the HMAC value of the current slot in procedure -$\Call{PutDataEntries}{}$} \\ -\textit{$hmac_{p_p}$ = the HMAC value of the previous slot -($hmac_{p_p} = \emptyset$ for the first slot) in procedure -$\Call{PutDataEntries}{}$} \\ -\textit{$id_{self}$ = machine Id of this client} \\ -\textit{$sl_{last}$ = info of last slot in queue = - $\tuple{s_{last},sv_{last},id_{last}}$ (initially $\emptyset$)} \\ -\textit{$sz$ = expected size of received slots from server} \\ -\textit{$th_p$ = threshold number of dead slots for a resize to happen} \\ -\textit{$m'_p$ = offset added to $max$ for resize} \\ -\textit{$reinsert_{qs}$ = boolean to decide $qs$($max_g$) reinsertion} \\ -\textit{$KV$ = set of $\tuple{ck, \tuple{k,v}}$ of kv entries on client} \\ -\textit{$SS$ = set of $\tuple{cs, \tuple{id,s_{last}}}$ of ss entries on client} \\ -\textit{$CR$ = set of $\tuple{cc, \tuple{s_{col},id_{col}}}$ of cr entries on client} \\ -\textit{$SL_p$ = set of returned slots on client} \\ -\textit{SK = Secret Key} \\ \\ -\textbf{Helper Functions} \\ -$CreateDat(s,id,hmac_p,DE,hmac_c)=Dat_s=\tuple{s,id,hmac_p,DE,hmac_c}$ \\ -$CreateSS(id_s,s_{s_{last}})=\tuple{id_s,s_{s_{last}}} = ss_s$ \\ -$CreateQS(max'_s)=qs_s$ \\ -$CreateCR(s_s,id_s)=\tuple{s_s,id_s} = cr_s$ \\ -$Encrypt(Dat_s,SK_s)=sv_s$ \\ -$GetColSeqN(SL_s,s_s)= \tuple{s, sv}$ \textit{such that} $\tuple{s, sv} -\in SL_s \wedge \forall \tuple{s_s, sv_s} \in SL_s, s = s_s$ \\ -$GetKVPair(KV_s,k_s)= \tuple{ck,\tuple{k, v}}$ \textit{such that} -$\tuple{ck,\tuple{k, v}} \in KV_s \wedge -\forall \tuple{ck_s,\tuple{k_s, v_s}} \in KV_s, k = k_s$ \\ - -\begin{algorithmic}[1] -\Function{Put}{$KV_s,\tuple{k_s,v_s}$} \Comment{Interface function to update a key-value pair} -\State $\tuple{ck_s,\tuple{k_s,v_t}} \gets GetKVPair(KV_s,k_s)$ -\If{$\tuple{ck_s,\tuple{k_s,v_t}} = \emptyset$} - \State $KV_s \gets KV_s \cup \{\tuple{ck_p, \tuple{k_s,v_s}}\}$ - \State $ck_p \gets ck_p + 1$ -\Else - \State $KV_s \gets (KV_s - \{\tuple{ck_s, \tuple{k_s,v_t}}\}) \cup - \{\tuple{ck_s, \tuple{k_s,v_s}}\}$ -\EndIf -\State \Return{$KV_s$} -\EndFunction -\end{algorithmic} - -\begin{algorithmic}[1] -\Function{PutSSPair}{$SS_s,\tuple{id_s,s_{s_{last}}}$}\Comment{Insert a set of $ss$ entries} -\State $SS_s \gets SS_s \cup \{\tuple{cs_p, \tuple{id_s,s_{s_{last}}}}\}$ -\State $cs_p \gets cs_p + 1$ -\State \Return{$SS_s$} -\EndFunction -\end{algorithmic} - -\begin{algorithmic}[1] -\Function{PutCRPair}{$CR_s,\tuple{s_s,id_s}$}\Comment{Insert a set of $cr$ entries} -\State $CR_s \gets CR_s \cup \{\tuple{cc_p, \tuple{s_s,id_s}}\}$ -\State $cc_p \gets cc_p + 1$ -\State \Return{$CR_s$} -\EndFunction -\end{algorithmic} - -\begin{algorithmic}[1] -\Function{CheckResize}{$MS_s,th_s,max_t,m'_s$} -\State $s_{last_{min}} \gets MinLastSeqN(MS_s)$ -\State $s_{last_{max}} \gets MaxLastSeqN(MS_s)$ -\State $n_{live} \gets s_{last_{max}} - s_{last_{min}} + 1$\Comment{Number of live slots} -\State $n_{dead} \gets max_t - n_{live}$ -\If{$n_{dead} \leq th_s$} - \State $max'_s \gets max_t + m'_s$ -\Else - \State $max'_s \gets \emptyset$ -\EndIf -\State \Return{$max'_s$} -\EndFunction -\end{algorithmic} - -\begin{algorithmic}[1] -\Function{CheckSLFull}{$MS_s,max_t$}\Comment{Check if $ss$ is needed} -\State $s_{last_{min}} \gets MinLastSeqN(MS_s)$ -\State $s_{last_{max}} \gets MaxLastSeqN(MS_s)$ -\State $n_{live} \gets s_{last_{max}} - s_{last_{min}}$\Comment{Number of live slots} -\State $n_{dead} \gets max_t - n_{live}$ -\State \Return {$n_{dead} = 0$} -\EndFunction -\end{algorithmic} - -\begin{algorithmic}[1] -\Function{HandleCollision}{$SL_s,s_s$} -\If{$SL_s = \emptyset$} - \State \Call{Error}{'No slots received from server'} -\EndIf -\State $\tuple{s_{col},sv_{col}} \gets GetColSeqN(SL_s,s_s)$ -\State $Dat_{col} \gets Decrypt(SK,sv_{col})$ -\State $id_{col} \gets GetMacId(Dat_{col})$ -\State $cr_s \gets CreateCR(s_{col},id_{col})$ -\State $\Call{ProcessSL}{SL_s}$ -\State \Return{$cr_s$} -\EndFunction -\end{algorithmic} - -\begin{algorithmic}[1] -\Procedure{CheckLastSlot}{$sl_{s_{last}}$} -\State $s_s \gets GetLastS(sl_{s_{last}})$ -\State $sv_s \gets GetSV(sl_{s_{last}})$ -\State $Dat_s \gets Decrypt(SK,sv_s)$ -\State $DE_s \gets GetDatEnt(Dat_s)$ -\ForAll{$de_s \in DE_s$} - \State $live \gets \Call{CheckLiveness}{s_s,de_s}$ - \If{$live$} - \If{$type(de_s) = ``kv"$} - \State $\tuple{k_s,v_s} \gets GetKV(de_s)$ - \State $KV \gets \Call{PutKVPair}{KV,\tuple{k_s,v_s}}$ - \ElsIf{$type(de_s) = ``ss"$} - \State $\tuple{id_s,s_{s_{last}}} \gets GetSS(de_s)$ - \State $SS \gets \Call{PutSSPair}{SS,\tuple{id_s,s_{s_{last}}}}$ - \ElsIf{$type(de_s) = ``cr"$} - \State $\tuple{s_s,id_s} \gets GetCR(de_s)$ - \State $CR \gets \Call{PutCRPair}{CR,\tuple{s_s,id_s}}$ - \ElsIf{$type(de_s) = ``qs"$} - \State $reinsert_{qs} \gets true$ - \EndIf - \EndIf -\EndFor -\EndProcedure -\end{algorithmic} - -\begin{algorithmic}[1] -\Function{CheckLiveness}{$s_s,de_s$} -\State $live \gets true$ -\If{$de_s = kv$} - \State $s_l \gets GetLivEntLastS(LV,de_s)$ - \If{$s_l = \emptyset \lor s_s < s_l$} - \State $live \gets false$ - \EndIf -\ElsIf{$de_s = ss$} - \State $ss_s \gets GetSS(de_s)$ - \State $ss_l \gets GetLiveSS(SS_{live},ss_s)$ - \If{$ss_l = \emptyset$} - \State $live \gets false$ - \EndIf -\ElsIf{$de_s = cr$} - \State $cr_s \gets GetCR(de_s)$ - \State $cr_l \gets GetLiveCR(CR_{live},cr_s)$ - \If{$cr_l = \emptyset$} - \State $live \gets false$ - \EndIf -\ElsIf{$de_s = qs$} - \State $qs_s \gets GetQS(de_s)$ - \If{$qs_s \neq max_g$} - \State $live \gets false$ - \EndIf -\Else - \State \Call{Error}{'Unrecognized $de$ type'} -\EndIf -\State \Return{$live$} -\EndFunction -\end{algorithmic} - -\begin{algorithmic}[1] -\Function{CreateSlotSeq}{$sl_s$} -\State $id_s \gets GetID(sl_s)$ -\State $s_{s_{last}} \gets GetLastS(sl_s)$ -\State $ss_s \gets CreateSS(id_s,s_{s_{last}})$ -\State \Return{$\tuple{ss_s}$} -\EndFunction -\end{algorithmic} - -\begin{algorithmic}[1] -\Function{AddQueSta}{$DE_s,max'_s,cp_s$}\Comment{Insert a $qs$} -\State $DE_{ret} \gets \emptyset$ -\State $qs_s \gets max'_s$ -\State $DE_{ret} \gets DE_s \cup \{qs_s\}$ -\State $cp_s \gets cp_s - 1$ -\State \Return{$\tuple{DE_{ret},cp_s}$} -\EndFunction -\end{algorithmic} - -\begin{algorithmic}[1] -\Function{GetKVPairs}{$DE_s,KV_s,cp_s$} -\State $DE_{ret} \gets \emptyset$ -\If{$|KV_s| \leq cp_s$}\Comment{$KV$ set can span multiple slots} - \State $DE_{ret} \gets DE_s \cup - \{\tuple{k_s,v_s} \mid \tuple{ck_s,\tuple{k_s,v_s}} \in KV_s\}$ -\Else - \State $DE_{ret} \gets DE_s \cup - \{\tuple{k_s,v_s} \mid \tuple{ck_s,\tuple{k_s,v_s}} \in KV_s, - ck_g \leq ck_s < ck_g + cp_s\}$ -\EndIf -\State \Return{$\tuple{DE_{ret}}$} -\EndFunction -\end{algorithmic} - -\begin{algorithmic}[1] -\Function{GetSSPairs}{$DE_s,SS_s,cp_s$} -\State $DE_{ret} \gets \emptyset$ -\If{$|SS_s| \leq cp_s$}\Comment{$SS$ set can span multiple slots} - \State $DE_{ret} \gets DE_s \cup - \{\tuple{id_s,s_{s_{last}}} \mid \tuple{cs_s,\tuple{id_s,s_{s_{last}}}} \in SS_s\}$ - \State $cp_s \gets cp_s - |SS_s|$ -\Else - \State $DE_{ret} \gets DE_s \cup - \{\tuple{id_s,s_{s_{last}}} \mid \tuple{cs_s,\tuple{id_s,s_{s_{last}}}} \in SS_s, - cs_g \leq cs_s < cs_g + cp_s\}$ - \State $cp_s \gets 0$ -\EndIf -\State \Return{$\tuple{DE_{ret},cp_s}$} -\EndFunction -\end{algorithmic} - -\begin{algorithmic}[1] -\Function{GetCRPairs}{$DE_s,CR_s,cp_s$} -\State $DE_{ret} \gets \emptyset$ -\If{$|CR_s| \leq cp_s$}\Comment{$CR$ set can span multiple slots} - \State $DE_{ret} \gets DE_s \cup - \{\tuple{s_s,id_s} \mid \tuple{cc_s,\tuple{s_s,id_s}} \in CR_s\}$ - \State $cp_s \gets cp_s - |CR_s|$ -\Else - \State $DE_{ret} \gets DE_s \cup - \{\tuple{s_s,id_s} \mid \tuple{cc_s,\tuple{s_s,id_s}} \in CR_s, - cc_g \leq cc_s < cc_g + cp_s\}$ - \State $cp_s \gets 0$ -\EndIf -\State \Return{$\tuple{DE_{ret},cp_s}$} -\EndFunction -\end{algorithmic} - -\begin{algorithmic}[1] -\Procedure{PutDataEntries}{$th_p,m'_p$} -\State $success_p \gets false$ -\State $CR_p \gets \emptyset$ -\While{$\neg success_p$} - \State $DE_p \gets \emptyset$ - \State $s_p \gets MaxLastSeqN(MS)$ - \State $cp_p \gets cp$ - \State $max'_p \gets \Call{CheckResize}{MS,th_p,max_g,m'_p}$ - \If{$max'_p \neq \emptyset$}\Comment{Add a qs entry} - \State $\tuple{DE_p,cp_p} \gets \Call{AddQueSta}{DE_p,max'_p,cp_p}$ - \State $reinsert_{qs} \gets false$ - \Else\Comment{Check if there is $qs$ reinsertion} - \If{$reinsert_{qs}$} - \State $\tuple{DE_p,cp_p} \gets \Call{AddQueSta}{DE_p,max_g,cp_p}$ - \State $reinsert_{qs} \gets false$ - \EndIf - \EndIf - \If{$SS \neq \emptyset$}\Comment{Add $ss$ entries} - \State $\tuple{DE_p,cp_p} \gets \Call{GetSSPairs}{DE_p,SS,cp_p}$ - \EndIf - \If{$CR \neq \emptyset$}\Comment{Add $cr$ entries} - \State $\tuple{DE_p,cp_p} \gets \Call{GetCRPairs}{DE_p,CR,cp_p}$ - \EndIf - \State $\tuple{DE_p,cp_p} \gets \Call{GetKVPairs}{DE_p,KV,cp_p}$\Comment{Add $kv$ entries} - \State $hmac_{c_p} \gets Hmac(DE_p,SK)$ - \State $Dat_p \gets CreateDat(s_p,id_{self},hmac_{p_p},DE_p,hmac_{c_p})$ - \State $hmac_{p_p} \gets hmac_{c_p}$ - \State $sv_p \gets Encrypt(Dat_p,SK)$ - \State $\tuple{success_p,SL_p} \gets \Call{PutSlot}{s_p,sv_p,max'_p}$ - \If{$\neg success_p$} - \State $cr_p \gets \Call{HandleCollision}{SL_p,s_p}$ - \State $\tuple{s_{p_{col}},id_{p_{col}}} \gets GetCR(cr_p)$ - \State $CR \gets \Call{PutCRPair}{CR,\tuple{s_{p_{col}},id_{p_{col}}}}$ - \EndIf -\EndWhile -\State $MS \gets \Call{UpdateLastSeqN}{id_{self},s_p,MS}$ -\If{$|DE_p| = cp$}\Comment{Update set counters} - \State $ck_g \gets ck_g + cp_p$\Comment{Middle of set} - \State $cs_g \gets cs_g + |SS|$ - \State $cc_g \gets cc_g + |CR|$ -\Else\Comment{End of set} - \State $ck_g \gets 0$ - \State $cs_g \gets 0$ - \State $cc_g \gets 0$ -\EndIf -\State $need_p \gets \Call{CheckSLFull}{MS,max_g}$ -\If{$need_p$}\Comment{SL on server is full} - \State $\Call{CheckLastSlot}{sl_{last}}$\Comment{Salvage entries from expunged slot} - \State $ss_p \gets \Call{CreateSlotSeq}{sl_{last}}$ - \State $\tuple{id_p,s_{p_{last}}} \gets GetSS(ss_p)$ - \State $SS \gets \Call{PutSSPair}{SS,\tuple{id_p,s_{p_{last}}}}$\Comment{Add ss} -\EndIf -\EndProcedure -\end{algorithmic} - -%\note{Lots of problems with PutDataEntries: (1) What happens if lose network connectivity after adding the key value pair, but before reinserting the last slot? You probably need to create space first and then insert your data entry... (2) What if reinsertlastslot kicks something else important out? What if the server rejects our update because it is out of date? At the very least, any putdataentries function w/o a loop is wrong!} - -%\note{General comments... Work on structuring things to improve readability... This include names of functions/variables, how things are partitioned into functions, adding useful comments,...} - -%\note{Also Missing liveness state definition in algorithm...} - - -\subsection{Formal Guarantees} -\subsubsection{Definitions} - -\begin{defn}[Message] -A message $\mathsf{t}$, is the tuple -\begin{center} -$\mathsf{t = \tuple{s, E(Dat_s)}}$ \\ -$\mathsf{Dat_t = \tuple{s,id,hmac_p, DE,hmac_c}}$ -\end{center} -containing $\mathsf{s}$ as sequence number and $\mathsf{Dat_t}$ as its -encrypted contents. $\mathsf{Dat_t}$ consists of $\mathsf{s}$, -$\mathsf{id}$ as machine ID of the sender, $\mathsf{hmac_p}$ as HMAC -from a previous message, $\mathsf{DE}$ as set of data entries, and -$\mathsf{hmac_c}$ as HMAC from message $\mathsf{t}$ respectively. -\end{defn} - -\begin{defn}[Equality] -Two messages $\mathsf{t}$ and $\mathsf{u}$ are equal if their $\mathsf{s}$, -and $\mathsf{Dat_t}$ are exactly the same. -\end{defn} - -\begin{defn}[Parent] -A parent of a message $\mathsf{t}$ is the message $\mathsf{p_t}$, -unique by the correctness of HMACs in $\mathsf{Dat_t}$, such that -$\mathsf{hmac_p(t) = hmac_c(p_t)}$. -\end{defn} - -\begin{defn}[Chain] -A chain of messages with length $\mathsf{n \ge 1}$ is a message sequence -$\mathsf{R = (r_s, r_{s+1}, ..., r_{s+n-1})}$ such that for every sequence -number $\mathsf{s < k \le s+n-1}$, $\mathsf{r_k}$ has sequence number -$\mathsf{k}$ and is the parent of $\mathsf{r_{k-1}}$. -\end{defn} - -\begin{defn}[Partial sequence] -A partial sequence $\mathsf{P}$ is a sequence of messages, no two -with the same sequence number, that can be divided into disjoint chains. -\end{defn} - -\begin{defn}[Total sequence] -A total sequence $\mathsf{T =}$ $\mathsf{(t_1, t_2, ..., t_n)}$ with -length $\mathsf{n}$ is a chain of messages that starts at $\mathsf{s = 1}$. -\end{defn} - -\begin{defn}[Path] -The path of a message $\mathsf{t}$ is the chain that starts at $\mathsf{s = 1}$ -and whose last message is $\mathsf{t}$. The uniqueness of a path follows -from the uniqueness of a parent. -\end{defn} - -\begin{defn}[Consistency] -A partial sequence $\mathsf{P}$ is consistent with a total sequence -$\mathsf{T}$ of length $\mathsf{n}$ if for every message $\mathsf{p \in P}$ -with $\mathsf{s_p \leq n}$, $\mathsf{t_{s_p} = p}$. This implies that -$\mathsf{\{p \in P | s_p \le n\}}$ is a partial sequence of $\mathsf{T}$. -\end{defn} - -\begin{defn}[Transitive closure] -Transitive closure set at sequence number $\mathsf{s_n}$ is a set -$\mathsf{\mathscr{S}}$ of clients comprising a connected component of an -undirected graph, where two clients are connected by an edge if they both -received the same message $\mathsf{t}$ with sequence number $\mathsf{s_t > s_n}$. -\end{defn} - -\subsubsection{Lemmas and Proofs} - -\begin{prop} -\label{prop:parentmessage} -Every client $\mathsf{J}$ who sends a message $\mathsf{t}$ -has parent $\mathsf{p_t}$ as its latest stored message, and -$\mathsf{s_t = s_{p_t} + 1}$. -\end{prop} -\begin{proof} True by definition, because $J$ sets -$\mathsf{hmac_p(t) = hmac_c(p_t)}$ and -$\mathsf{s_t = }$ $\mathsf{s_{p_t + 1}}$ when a message -is sent. -\end{proof} - -\begin{prop} -\label{prop:rejectedmessage} -If a rejected message entry is added to the set $\mathsf{CR}$ -at sequence number $\mathsf{s}$, the message will remain in $\mathsf{CR}$ -until every client has seen it. -\end{prop} -\begin{proof} Every $\mathsf{CR}$ entry $\mathsf{cr}$ remains in the queue until it -reaches the tail, and is refreshed by the next sender $\mathsf{J}$ at that time if -$\mathsf{min(MS) > s_{cr}}$; that is, until every client has sent a message with -sequence number greater than $\mathsf{s_{cr}}$. Because every client who sends a -message with sequence number $\mathsf{s}$ has the state of the set $\mathsf{SL}$ at -$\mathsf{s - 1}$, this client will have seen the message at $\mathsf{s_{cr}}$. -\end{proof} - -\begin{figure}[h] - \centering - \xymatrix{ & & L \\ -\dots \ar[r] & q \ar[dr]_{J} \ar[r]^{K} & l_1 \ar[r] & l_2 \ar[r] & \dots \ar[r] & m \ar[r] & \dots \ar[r] & l_n = u \\ -& & r_1 \ar[r] & r_2 \ar[r] & \dots \ar[r] & r_m = t \\ -& & R -\save "2,3"."2,8"*+\frm{^\}} -\save "3,3"."3,6"*+\frm{_\}} -\restore -\restore -} -\caption{By \textbf{Lemma \ref{lem:twomessages}}, receiving both $t$ and $u$ here is impossible.} -\end{figure} - -\begin{lem} -\label{lem:twomessages} -Two messages are received without errors by a client $\mathsf{C}$; -call them $\mathsf{t}$ and $\mathsf{u}$ such that $\mathsf{s_t \le s_u}$. -Then $\mathsf{t}$ is in the path of $\mathsf{u}$. -\end{lem} -\begin{proof} -Assume that there are some pairs of messages $\mathsf{(t,u)}$ that violate this lemma. -Take a specific $\mathsf{(t,u)}$ such that $\mathsf{s_u}$ is minimized, and -$\mathsf{s_t}$ is maximized for this choice of $\mathsf{s_u}$. We will show that $\mathsf{C}$ -cannot receive both $\mathsf{t}$ and $\mathsf{u}$ without throwing an error. - -Clearly $\mathsf{C}$ will throw an error if $\mathsf{s_t = s_u}$. So -$\mathsf{s_t < s_u}$. Additionally, if $\mathsf{C}$ receives $\mathsf{u}$ before -$\mathsf{t}$, this will cause it to throw an error, so $\mathsf{t}$ is received -before $\mathsf{u}$. We will prove that an error occurs upon receipt of $\mathsf{u}$. - -Let $\mathsf{r_1}$ be the earliest member of the path of $\mathsf{t}$ that is -not in the path of $\mathsf{u}$, and $\mathsf{q}$ be its parent. Message -$\mathsf{q}$, the last common ancestor of $\mathsf{t}$ and $\mathsf{u}$, must exist, -since all clients and the server were initialized with the same state. Let -$\mathsf{l_1}$ be the successor of $\mathsf{q}$ that is in the path of $\mathsf{u}$; -we know $\mathsf{l_1 \neq r_1}$. Let $\mathsf{R = (r_1, r_2, \dots, r_{|R|} = t)}$ be -the distinct portion of the path of $\mathsf{t}$, and similarly let $\mathsf{L}$ -be the distinct portion of the path of $\mathsf{l_{|L|} = u}$. - -Let $\mathsf{J}$ be the client who sent $\mathsf{r_1}$; that is, such that -$\mathsf{{id_{self}}_J = GetMacID(r_1)}$, and $\mathsf{K}$ be the client who -sent $\mathsf{l_1}$. Because no client can send two messages with the same sequence number, and -$\mathsf{s_{r_1} = s_{l_1} = s_q + 1}$, $\mathsf{J \neq K}$. - -We also know the following facts: - -\begin{prop} -\label{prop:bothmessages} -No client sends both a message in $\mathsf{(r_2,...,t)}$ and a message in $\mathsf{(l_2,...,u)}$. -\end{prop} - -\begin{proof} -To send a message $\mathsf{p}$ that is the parent of some other -message, one must have received the parent of $\mathsf{p}$. Since -$\mathsf{u}$ is the message with smallest sequence number received by any -client that violates Lemma \ref{lem:twomessages}, no client receives both a message -in $\mathsf{r}$ and a message in $\mathsf{l}$. -\end{proof} - -\begin{prop} -\label{prop:seqnumb} -$\mathsf{C}$ does not receive any message with a -sequence number strictly between $\mathsf{s_t}$ and $\mathsf{s_u}$. -\end{prop} - -\begin{proof} If there were such a message with sequence number smaller than -$\mathsf{s_u}$, it would contradict the assumption that $\mathsf{u}$ is the -message with the least sequence number that violates Lemma \ref{lem:twomessages}. -\end{proof} - -There are two cases: -\begin{itemize} -\item Case 1: $\mathsf{J}$ did not send a message in $\mathsf{L}$. Then, where $\mathsf{s_{t_J}}$ -is the greatest sequence number of the messages that client $\mathsf{J}$ sent in -the path of message $\mathsf{t}$, $\mathsf{s_{t_J} > s_{q_J} = s_{u_J}}$. -\begin{itemize} -\item Case 1.1: $\mathsf{C}$ never updates its slot sequence list $\mathsf{SS}$ -between receiving $\mathsf{t}$ and receiving $\mathsf{u}$; this can only happen if -$\mathsf{s_t = s_u - 1}$. Since $\mathsf{t}$ is not the parent of $\mathsf{u}$, -$\mathsf{hmac_p(u) \neq hmac_c(t)}$, causing $\mathsf{C}$ to throw an error. -\item Case 1.2: Case 1.1 does not occur; therefore, $\mathsf{C}$ must update -its slot sequence list $\mathsf{SS}$ at some point between receiving $\mathsf{t}$ -and $\mathsf{u}$. -The latest sequence number of $\mathsf{J}$ decreases during this time, which -means it must decrease when some message is received, which means $\mathsf{C}$ -throws an error in the $\mathsf{CheckLastSeqN()}$ subroutine. -\end{itemize} - -\item Case 2: $\mathsf{J}$ sent at least one message in $\mathsf{L}$. Call the -first one $\mathsf{m}$. We know that $\mathsf{s_m > s_{r_1}}$, since -$\mathsf{J \neq K}$ and $\mathsf{m \neq l_1}$. Message $\mathsf{r_1}$ must be sent -either before or after $\mathsf{m}$. -\begin{itemize} -\item Case 2.1: Client $\mathsf{J}$ sends $\mathsf{m}$, and then $\mathsf{r_1}$. -Before sending $\mathsf{m}$, the greatest sequence number of a message that -$\mathsf{J}$ has received, $\mathsf{{s_{last}}_J}$, must be equal to -$\mathsf{s_m - 1 \ge s_{r_1}}$. Since $\mathsf{{s_{last}}_J}$ never decreases, -client $\mathsf{J}$ cannot then send a message with sequence number -$\mathsf{s_{r_1}}$, a contradiction. -\item Case 2.2: Client $\mathsf{J}$ sends $\mathsf{r_1}$, and then $\mathsf{m}$. -Let $\mathsf{X = (r_1 = x_1, \dots , x_n)}$ be the list of messages $\mathsf{J}$ sends -starting before $\mathsf{r_1}$ and ending before $m$; clearly these all have sequence -number $\mathsf{s_p = s_q + 1}$. -\begin{itemize} -\item Case 2.2.1: Some message in $\mathsf{X}$ was accepted. Before sending $\mathsf{m}$, -$\mathsf{J}$'s value in $\mathsf{MS_J}$ for its own latest sequence number would -be strictly greater than $\mathsf{s_{q_J}}$. If there is a sequence of messages with -contiguous sequence numbers that $\mathsf{J}$ receives between $\mathsf{r_1}$ and -$\mathsf{m}$, $\mathsf{J}$ throws an error for a similar reason as Case 1.1. Otherwise, -when preparing to send $\mathsf{m}$, $\mathsf{J}$ would have received an update of its -own latest sequence number as at most $\mathsf{s_{q_J}}$. $J$ throws an error before -sending $\mathsf{p}$, because its own latest sequence number decreases. -\item Case 2.2.2: All messages in $\mathsf{X}$ were rejected, making $\mathsf{m}$ -the first message of $\mathsf{J}$ that is accepted after $\mathsf{r_1}$. - -We will show that $\mathsf{C}$ sees $\mathsf{r_1}$. Assume not. Then $\mathsf{(r_2, ..., u)}$ -must have at least $\mathsf{{max_g}_C} \geq 2$ messages for $\mathsf{r_1}$ to fall off the -end of the queue. Consider the sender of $\mathsf{r_3}$ and call it $\mathsf{H}$. -$\mathsf{H \neq J}$ by Proposition \ref{prop:bothmessages} and the existence of $\mathsf{m}$. -Since $\mathsf{H \neq J}$, then by Proposition \ref{prop:bothmessages} it could not also -have sent a message in $\mathsf{(l_2,..., u)}$. Therefore, $\mathsf{s_{u_H} < s_q + 2 = s_{t_H}}$, -so upon receipt of $\mathsf{u}$, $\mathsf{C}$ will throw an error by the decrease in a -last sequence number similar to Case 1, a contradiction. - -Now that we know that $\mathsf{C}$ sees $\mathsf{r_1}$, note that C receives $\mathsf{u}$ -immediately after $\mathsf{t}$ by Proposition \ref{prop:seqnumb}. Therefore, -$\mathsf{C}$ could not have seen a message after $\mathsf{t}$ with sequence number less -than $\mathsf{s_m}$. In the $\mathsf{PutDataEntries()}$ subroutine, $\mathsf{J}$ adds every -$\mathsf{cr}$ entry that contains sequence number $\mathsf{s}$ and machine ID -$\mathsf{id}$ of the messsages that win in the collisions before $\mathsf{m}$ into -$\mathsf{CR}$; $\mathsf{CR}$ keeps the collection of live $\mathsf{cr}$ entries, namely -those which not all clients have seen. Hence, for every $\mathsf{i}$, $\mathsf{1 \leq i < |X|}$, -the collision winner that has collided with $\mathsf{x_i}$ will be recorded appropriately. Since all the $\mathsf{cr}$ entries that record the results of the collisions before $\mathsf{p}$ will also be seen when $\mathsf{u}$ -is received, and $\mathsf{C}$ sees $\mathsf{r_1}$, ${l_1}$ will be recorded in a $\mathsf{cr}$ entry as the winner in the -collision against ${r_1}$. - -When $\mathsf{C}$ receives $\mathsf{u}$, if $\mathsf{C}$ -has seen the $\mathsf{cr}$ entry that records the collision at index $\mathsf{s_q + 1}$, it will throw -an error from the mismatch of $\mathsf{\tuple{s_q+1, id_J}}$ with -$\mathsf{\tuple{s_q+1, id_K}}$ in the corresponding $\mathsf{cr}$ entry. - -\end{itemize} -\end{itemize} - -\end{itemize} -\end{proof} - -\begin{lem} -\label{lem:pathmessages} -If there are two messages $\mathsf{t}$ and $\mathsf{u}$, with -$\mathsf{s_t \leq s_u}$, such that $\mathsf{t}$ is in the path of $\mathsf{u}$, -then for any message $\mathsf{p}$ with $\mathsf{s_p \leq s_t}$, iff $\mathsf{p}$ is in -the path of $\mathsf{t}$, it is in the path of $\mathsf{u}$. -\end{lem} - -\begin{proof} -If $\mathsf{s_t = s_u}$ or $\mathsf{s_p = s_t}$, then we are done, because the two -relevant messages are the same. If they are different messages, then: -\begin{itemize} -\item Reverse direction: The definition of $\mathsf{t}$ being in the path of -$\mathsf{u}$ is the existence of a message sequence $\mathsf{(\dots, t, \dots, u)}$ -such that each message except $\mathsf{u}$ is the parent of the succeeding message. -The path of $\mathsf{u}$ must contain some message with sequence number $\mathsf{s_p}$; -because $\mathsf{p}$ is in the path of $\mathsf{u}$, this message is $\mathsf{p}$ -itself. The path of $\mathsf{t}$ is then the prefix of this path ending at $\mathsf{t}$, -which clearly contains $\mathsf{p}$. - -\item Forward direction: The path of $\mathsf{t}$ is a substring of the path of -$\mathsf{u}$, so if the path of $\mathsf{t}$ contains $\mathsf{p}$, so does the path -of $\mathsf{u}$. -\end{itemize} -\end{proof} - -\begin{theorem} -Suppose that there is a transitive closure set $\mathsf{\mathscr{S}}$ of clients, -at sequence number $\mathsf{s_n}$. Then there is some total sequence $\mathsf{T}$ of -length $\mathsf{n}$ such that every client $\mathsf{C}$ in $\mathsf{\mathscr{S}}$ -sees a partial sequence $\mathsf{P_C}$ consistent with $\mathsf{T}$. -\end{theorem} - -\begin{proof} - -The definition of consistency of $\mathsf{P_C}$ with $\mathsf{T}$ is that every message -$\mathsf{p \in P_C}$ with sequence number $\mathsf{s_p \le s_n}$ is equal to the message -in that slot in $\mathsf{T}$. Let $\mathsf{C_1}$ be some client in the transitive closure -set, with partial sequence $\mathsf{P_{C_1}}$, and let $\mathsf{u}$ be some message with -$\mathsf{s_u > s_n}$ that $\mathsf{C_1}$ shares with another client. Then let $\mathsf{T}$ -be the portion of the path of $\mathsf{u}$ ending at sequence number $\mathsf{s_n}$ and -$\mathsf{t}$ be the message at that sequence number. Clearly, by Lemma \ref{lem:twomessages}, -$\mathsf{P_{C_1}}$ is consistent with $\mathsf{T}$. We will show that, for every other client -$\mathsf{D}$ with partial sequence $\mathsf{P_D}$, $\mathsf{P_D}$ has some message whose path -includes $\mathsf{t}$. Because $\mathsf{D}$ is in the transitive closure, there is a sequence -of clients $\mathsf{\mathscr{C} = (C_1, C_2, ..., D)}$ from $\mathsf{C_1}$ to $\mathsf{D}$, -where each shares an edge with the next. -We prove by induction that $\mathsf{P_D}$ has a message whose path includes $\mathsf{t}$. -\begin{itemize} -\item Base case: $\mathsf{P_{C_1}}$ includes $\mathsf{u}$, whose path includes $\mathsf{t}$. - -\item Inductive step: Each client in $\mathsf{\mathscr{C}}$ has a partial sequence with a message -that includes $\mathsf{t}$ if the previous client does. Suppose $\mathsf{P_{C_k}}$ has -a message $\mathsf{w}$ with a path that includes $\mathsf{t}$, and shares message $\mathsf{x}$ -with $\mathsf{P_{C_{k+1}}}$ such that $\mathsf{s_x > s_n}$. By Lemma \ref{lem:twomessages}, -$\mathsf{w}$ or $\mathsf{x}$, whichever has the least sequence number, is in the path of the other, -and therefore by Lemma \ref{lem:pathmessages}, $\mathsf{t}$ is in the path of $\mathsf{x}$. - -\item Let $\mathsf{z}$ be the message of $\mathsf{D}$ whose path includes $\mathsf{t}$. -By Lemma \ref{lem:twomessages}, every message in $\mathsf{P_D}$ with sequence number smaller -than $\mathsf{s_w}$ is in the path of $\mathsf{z}$. Since $\mathsf{t}$ is in the path of -$\mathsf{z}$, every message in $\mathsf{P_D}$ with smaller sequence number than -$\mathsf{s_t = s_n}$ is in $\mathsf{T}$. -Therefore, $\mathsf{P_D}$ is consistent with $\mathsf{T}$. - -\end{itemize} -\end{proof} - -\subsection{Future Work} -\paragraph{Support Messages} - A message is dead once receiving machine sends an entry with a newer - sequence identifier - -\paragraph{Persistent data structures} - Root object w/ fields - Other objects can be reachable from root - Each object has its own entries - Dead objects correspond to dead - -\paragraph{Multiple App Sharing} - -Idea is to separate subspace of entries... Shared with other cloud... -\end{document} diff --git a/doc/makefile b/doc/makefile deleted file mode 100644 index cff4a15..0000000 --- a/doc/makefile +++ /dev/null @@ -1,8 +0,0 @@ -LATEX := pdflatex -halt-on-error - -default: - $(LATEX) iotcloud.tex - -clean: - rm -f *.dvi *.log *.aux *.blg *.bbl *~ - rm -f iotcloud.ps iotcloud.pdf diff --git a/doc2/iotcloud.tex b/doc2/iotcloud.tex deleted file mode 100644 index 1d760d7..0000000 --- a/doc2/iotcloud.tex +++ /dev/null @@ -1,1860 +0,0 @@ -\documentclass[11pt]{article} -\newcommand{\tuple}[1]{\ensuremath \langle #1 \rangle} -\usepackage{color} -\usepackage{amsthm} -\usepackage{amsmath} -\usepackage{graphicx} -\usepackage{mathrsfs} -\usepackage{amssymb} -\usepackage{algpseudocode}% http://ctan.org/pkg/algorithmicx -\usepackage[all]{xy} -\usepackage{varwidth} - -\newtheorem{theorem}{Theorem} -\newtheorem{prop}{Proposition} -\newtheorem{lem}{Lemma} -\newtheorem{defn}{Definition} -\newcommand{\note}[1]{{\color{red} \bf [[#1]]}} -\newcommand{\push}[1][1]{\hskip\dimexpr #1\algorithmicindent\relax} -\newcommand*\xor{\mathbin{\oplus}} -\algnewcommand{\LeftComment}[1]{\Statex \(\triangleright\) #1} -\begin{document} - - -\setlength\parindent{0pt} % Removes all indentation from paragraphs - comment this line for an assignment with lots of text - - -\section{\textbf{Introduction}} - - -\section{Approach} - -\subsection{Keys} - -Each device has: user id + password - -Server login is: -hash1(user id), hash1(password) - -Symmetric Crypto keys is: -hash2(user id | password) - -Server has finite length queue of entries + max\_entry\_identifier + -server login key - -\subsection{Entry layout} -Each entry has: -\begin{enumerate} -\item Sequence identifier -\item Random IV (if needed by crypto algorithm) -\item Encrypted payload -\end{enumerate} - -Payload has: -\begin{enumerate} -\item Sequence identifier -\item Machine id (most probably something like a 64-bit random number -that is self-generated by client) -\item HMAC of previous slot -\item Data entries -\item HMAC of current slot -\end{enumerate} - -A data entry can be one of these: -\begin{enumerate} - \item A transaction: - \begin{itemize} - \item Contains a sequence number, a set of key value pair updates and a guard condition that can be evaluated. - \item Must have the same arbitrator for all its key value pair updates and reads within the guard condition - \end{itemize} - - \item A Commit - \newline{Commits a transaction into the block chain. Until a transaction is committed, no client can be sure if that transaction's key value updates will be used to update the state of the system. Once an arbitrator commits a transaction then that transaction becomes a permanent state change in the system. Transactions should be committed and aborted in order of their sequence numbers.} - - \item An Abort - \newline{An abort is used to show that a transactions key value update should not be used in the state change of the system. This occurs when the guard of a transaction evaluates to false meaning that the conditions under-which this transaction should be committed no longer exists in the system (another transaction could have been committed first that would have changed the system in a way that makes the current transaction invalid).} - - \item New Key: - \newline{This creates a new key and assignes an arbitrator to that key. Only the first new key message for a given key is valid. Once a new key message is inserted into the block chain it is never removed and no other new key entries for the same key name can be inserted into the block chain.} - - \item Slot sequence entry: Machine id + last message identifier - \newline {The purpose of this is to keep the record of the last slot from a certain client if a client's update has to expunge that other client's last entry from the queue. This is kept in the slot until the entry owner inserts a newer update into the queue.} - - \item Queue state entry: Includes queue size - \newline {The purpose of this is for the client to tell if the server lies about the number of slots in the queue, e.g. if there are 2 queue state entry in the queue, e.g. 50 and 70, the client knows that when it sees 50, it should expect at most 50 slots in the queue and after it sees 70, it should expect 50 slots before that queue state entry slot 50 and at most 70 slots. The queue state entry slot 70 is counted as slot number 51 in the queue.} - - \item Collision resolution entry: message identifier + machine id of a collision winner - \newline {The purpose of this is to keep keep track of the winner of all the collisions until all clients have seen the particular entry.} -\end{enumerate} - -\subsection{Live status} - -Live status of entries: -\begin{enumerate} - \item Transaction is live if it has not been committed or aborted yet. - - \item Abort is live until the machine ID that created the transaction that is being aborted inserts into the block chain a message with a sequence number greater than the abort (that client sees the abort). - - \item Commit is dead if for all key value updates in the commit there is a commit with the same key value update that is newer (larger sequence number). The committing client (arbitrator) will see those newer commits since it is the one that generates them. - - \item New Key messages are always kept alive. Keys can not be deleted. Deleted keys will cause arbitration to fail if a key is deleted then reassigned to a new client device for arbitration. - - \item Slot sequence number (of either a message version data or user-level data) is dead if there is a newer slot from the same machine. - - \item Queue state entry is dead if there is a newer queue state entry. - {In the case of queue state entries 50 and 70, this means that queue state entry 50 is dead and 70 is live. However, not until the number of slots reaches 70 that queue state entry 50 will be expunged from the queue. Further all entries before the 50 entry will also not be expunged until the queue size has reached 70} - - \item Collision resolution entry is dead if this entry has been seen by all clients after a collision happens. -\end{enumerate} - -When data is at the end of the queue ready to expunge, if: -\begin{enumerate} - \item If any entry is not dead it must be reinserted into the queue. - - \item If the slot sequence number is not dead, then a message sequence entry must be inserted. -\end{enumerate} - -\paragraph{Validation procedure on client:} -\begin{enumerate} - \item Decrypt each new slot in order. - \item For each slot: - (a) check its HMAC, and - (b) check that the previous entry HMAC field matches the previous entry (in case of a gap do not check for slots on gap margins). - \item That no slots are slots we have seen before (server trying to pass old slots). - - \item For all other machines, check that the latest sequence number is at least as large (never goes backwards). - - \item That the queue has a current queue state entry. - - \item That the number of entries received is consistent with the size specified in the queue state entry and/or the queue is growing in size. -\end{enumerate} - -\subsection{Resizing Queue} -Client can make a request to resize the queue. This is done as a write that combines: - (a) a slot with the message, and (b) a request to the server. The queue can only be expanded, never contracted; attempting to decrease the size of the queue will cause future clients to throw an error. - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -\subsection{The Arbitrator} -Each key has an arbitrator that makes the final decision when it comes to whether a specific transaction containing that key updates the state of the system or is aborted. This ensures that clients can make offline updates and then push those updates to the server at a later time. The arbitrator then tries to merge those updates and if possible will commit them into the current working state of the system. If not possible then the arbitrator will abort that transaction. The arbitrator arbitrates on transactions in order of transaction sequence number. - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -\section{Server Algorithm} -$s \in SN$ is a sequence number\\ -$sv \in SV$ is a slot's value\\ -$slot_s = \tuple{s, sv} \in SL \subseteq SN \times SV$ \\ \\ -\textbf{State} \\ -\textit{SL = set of live slots on server} \\ -\textit{max = maximum number of slots (input only for resize message)} \\ -\textit{n = number of slots} \\ \\ -\textbf{Helper Function} \\ -$MaxSlot(SL_s)= \tuple{s, sv} \mid \tuple{s, sv} -\in SL_s \wedge \forall \tuple{s_s, sv_s} \in SL_s, s \geq s_s$ \\ -$MinSlot(SL_s)= \tuple{s, sv} \mid \tuple{s, sv} -\in SL_s \wedge \forall \tuple{s_s, sv_s} \in SL_s, s \leq s_s$ \\ -$SeqN(slot_s = \tuple{s, sv})=s$ \\ -$SlotVal(slot_s = \tuple{s, sv})=sv$ \\ - -\noindent\fbox{% -\begin{varwidth}{\dimexpr\linewidth-2\fboxsep-2\fboxrule\relax} -\textbf{Get Slot:}\\ -Returns to the client the slots that have a sequence number that is greater than or equal to the sequence number that is in the requese.\\ -\begin{algorithmic}[1] -\Function{GetSlot}{$s_g$} -\State \Return{$\{\tuple{s, sv} \in SL \mid s \geq s_g\}$} -\EndFunction -\end{algorithmic}\end{varwidth}% -} - - -\noindent\fbox{% -\begin{varwidth}{\dimexpr\linewidth-2\fboxsep-2\fboxrule\relax} -\textbf{Get Slot:}\\ -Puts a slot in the server memory if the slot has the correct sequence number. Also resizes the server memory if needed.\\ -\begin{algorithmic}[1] -\Function{PutSlot}{$s_p,sv_p,max'$} -\If{$(max' \neq \emptyset)$} \Comment{Resize} -\State $max \gets max'$ -\EndIf -\State $\tuple{s_n,sv_n} \gets MaxSlot(SL)$\Comment{Last sv} -%\State $s_n \gets SeqN(\tuple{s_n,sv_n})$ -\If{$(s_p = s_n + 1)$} - \If{$n = max$} - \State $\tuple{s_m,sv_m} \gets MinSlot(SL)$\Comment{First sv} - \State $SL \gets SL - \{\tuple{s_m,sv_m}\}$ - \Else \Comment{$n < max$} - \State $n \gets n + 1$ - \EndIf - \State $SL \gets SL \cup \{\tuple{s_p,sv_p}\}$ - \State \Return{$(true,\emptyset)$} -\Else - \State \Return{$(false,\{\tuple{s,sv}\in SL \mid - s \geq s_p\})$} -\EndIf -\EndFunction -\end{algorithmic}\end{varwidth}% -} - - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -\section{\textbf{Client}} - -\subsection{\textbf{Client Notation Conventions}} -$k$ is key of entry \\ -$v$ is value of entry \\ -$size$ is a size (target size of the current block chain) \\ -$kv$ is a key-value pair $\tuple{k,v}$ \\ -$KV$ is a set of $kv$ \\ -$id$ is a machine ID \\ -$seq$ is a sequence number \\ -$hmac_p$ is the HMAC value of the previous slot \\ -$hmac_c$ is the HMAC value of the current slot \\ -$Guard$ is a set of$ \tuple{k,v,$logical operator$}$ which can be evaluated to a boolean \\ - -$trans$ is a transaction entry , $\tuple{seq, id, KV, Guard}$ \\ -$lastmsg$ is a last message entry, $\tuple{seq, id}$ \\ -$qstate$ is a queue state entry, $\tuple{size}$ \\ -$colres$ is a collision resolution entry, $\tuple{id, seq_{old}, seq_{new}, true \lor false}$ \\ -$newkey$ is a new key entry, $\tuple{k, id}$, $id$ is ID of arbitrator \\ -$commit$ is a commit transaction entry, $\tuple{seq_{trans},KV}$, id is id of arbitrator \\ -$abort$ is an abort transaction entry, $\tuple{seq_{trans},id_{trans}}$ \\ - - -$de$ is a data entry that can one of: $trans$, $lastmsg$, $qstate$, $colres$, $newkey$, $commit$, $abort$ \\ -$DE$ is a set of all data entries, possibly of different types, in a single message, set of $de$\\ - -$slotDat = \tuple{seq,id,DE,hmac_p,hmac_c}$ \\ -$slot = \tuple{seq, Encrpt(slotDat)}$\\ - -\subsection{\textbf{Client State}} - -\subsubsection{Constants} -$LOCAL\_ID$ = machine ID of this client.\\ -$RESIZE\_THRESH\_PERCENT$ = percent of slots that need to have live data to trigger a resize.\\ -$RESIZE\_PERCENT$ = percent that we should grow the block chain to.\\ -$DATA\_ENTRY\_SET\_MAX\_SIZE$ = max size that a data entry set can have (in bytes).\\ -$DEAD\_SLOT\_COUNT$ = number of slots to keep dead if possible at the end of the block chain.\\ -$MAX\_RESCUE\_SKIPS$ = number of skips that are allowed when saving data entries.\\ - -\subsubsection{Primitive Variables} -$max\_size$ = max size of the block chain\\ - -\subsubsection{Sets and Lists} - -$PendingTransQueue$ = Queue of pending transactions that need to be pushed to the block chain, $\tuple{PendingTrans}$\\ -$PendingTrans= \tuple{KV, Guard} = \tuple{$set of key value pairs, set of guard conditions$}$.\\ -$Arbitrator$ = set of $\tuple{k,id}$ containing the key and its arbitrating device.\\ -$LastSlot$ = set of $\tuple{id, seq}$ containing the machine ID and the largest sequence number from that machine ID.\\ -$LocalSlots$ = set of slots that are in the clients local buffer (initially $\emptyset$), data is decrypted.\\ -$RejectedSlotList$ = ordered list of the sequence numbers of slots that this client tried to insert but were rejected.\\ -$CommittedKV$ = set of committed key value pairs (initially $\emptyset$).\\ -$SpeculatedKV$ = set of speculated key value pairs (initially $\emptyset$). - -\subsection{Helper Functions} -The following helper functions are needed:\\ - -$MaxSlot(SL_s)= \tuple{s, sv} \mid \tuple{s, sv} \in SL_s \wedge \forall \tuple{s_s, sv_s} \in SL_s, s \geq s_s$ \\ -$MinSlot(SL_s)= \tuple{s, sv} \mid \tuple{s, sv} \in SL_s \wedge \forall \tuple{s_s, sv_s} \in SL_s, s \leq s_s$ \\ - - -% Get Size -\noindent\fbox{% -\begin{varwidth}{\dimexpr\linewidth-2\fboxsep-2\fboxrule\relax} -\textbf{Get Byte Size:}\\ -Get the size in bytes of the thing that is passed in.\\ -\begin{algorithmic}[1] -\Function{GetSize}{$a$} - \State \Return{Size in bytes of $a$} -\EndFunction -\end{algorithmic}\end{varwidth}% -} - -% Error -\noindent\fbox{% -\begin{varwidth}{\dimexpr\linewidth-2\fboxsep-2\fboxrule\relax} -\textbf{ Error:}\\ -Prints an error message and halts the execution of the client.\\ -\begin{algorithmic}[1] -\Function{Error}{$msg$} - \State $Print(msg)$ - \State $Halt()$ -\EndFunction -\end{algorithmic}\end{varwidth}% -} - -% Get Next Sequence Number -\noindent\fbox{% -\begin{varwidth}{\dimexpr\linewidth-2\fboxsep-2\fboxrule\relax} -\textbf{Get Next Sequence Number:}\\ -Get the next sequence number for insertion into the block chain.\\ -\begin{algorithmic}[1] -\Function{GetNextSeq}{$k$} - \LeftComment{Get the largest known sequence number} - \State $seq_{ret} \gets seq$ such that $\tuple{id, seq}\in LastSlo \land (\forall \tuple{id', seq'} \in LastSlo, seq \geq seq')$\\ - - \LeftComment{Add one to the largest seq number to generate the new seq number} - \State \Return{$seq_{ret} + 1$} -\EndFunction -\end{algorithmic} -\end{varwidth}% -} - -% Get Arbitrator -\noindent\fbox{% -\begin{varwidth}{\dimexpr\linewidth-2\fboxsep-2\fboxrule\relax} -\textbf{Get Arbitrator:}\\ -Get the arbitrator for a given key.\\ -\begin{algorithmic}[1] -\Function{GetArbitrator}{$k$} - \State $\tuple{k_1,id_1} \gets \tuple{k_2,id_2} $ \textit{such that} $ \tuple{k_2,id_2} \in Arbitrator \land k_2=k$ - \State \Return{$id_1$} -\EndFunction -\end{algorithmic} -\end{varwidth}% -} - -% Get Arbitrator KV -\noindent\fbox{% -\begin{varwidth}{\dimexpr\linewidth-2\fboxsep-2\fboxrule\relax} -\textbf{Get Arbitrator for KV Set:}\\ -Get the arbitrator for a given key value set.\\ -\begin{algorithmic}[1] -\Function{GetArbitratorKV}{$KV$} - \State $\tuple{k,v} \gets \tuple{k',v'}$ such that $\tuple{k',v'} \in KV$ - \State $\tuple{k_1,id_1} \gets \tuple{k_2,id_2} $ \textit{such that} $ \tuple{k_2,id_2} \in Arbitrator \land k_2=k$ - \State \Return{$id_1$} -\EndFunction -\end{algorithmic} -\end{varwidth}% -} - -% Check Transaction arbitrator -\noindent\fbox{% -\begin{varwidth}{\dimexpr\linewidth-2\fboxsep-2\fboxrule\relax} -\textbf{Check Arbitrator for a Transaction:}\\ -Check that the arbitrators for a given set are all the same arbitrator.\\ -\begin{algorithmic}[1] -\Function{CheckArbitrator}{$PendingTrans_a$} - \State $id_{arb} \gets NULL$\\ - \State $\tuple{KV_a, Guard_a} \gets PendingTrans_a$ - - \ForAll{$\tuple{k',v'} \in KV_a$} - \State $id' \gets$ \Call{GetArbitrator}{$k'$}\\ - - \If{$id_{arb} = NULL$} - \State $id_{arb} \gets id'$ - \ElsIf{$id' \neq id_{arb}$} \Comment{Check all arbitrators are the same} - \State \Call{Error}{"Multiple arbitrators for key values in transaction."} - \EndIf - \EndFor - - \ForAll{$\tuple{k',v', lop'} \in Guard_a$} - \State $id' \gets$ \Call{GetArbitrator}{$k'$}\\ - - \If{$id_{arb} = NULL$} - \State $id_{arb} \gets id'$ - \ElsIf{$id' \neq id_{arb}$} \Comment{Check all arbitrators are the same} - \State \Call{Error}{"Multiple arbitrators for key values in transaction."} - \EndIf - \EndFor -\EndFunction -\end{algorithmic} -\end{varwidth}% -} - -% Get all Commits -\noindent\fbox{% -\begin{varwidth}{\dimexpr\linewidth-2\fboxsep-2\fboxrule\relax} -\textbf{Get all Commits:}\\ -Get all commits that are currently in the local block chain. Iterate over all the local slots and extract all the commits from each slot.\\ -\begin{algorithmic}[1] -\Function{GetCommits}{$ $} - \State $ComSet \gets \emptyset$ \Comment{Set of the commits}\\ - - \LeftComment{Iterate over all the slots saved locally} - \ForAll{$\tuple{s_1', \tuple{seq_2',id',DE',hmac_p',hmac_c'}} \in LocalSlots$} - \State $ComSet \gets ComSet \cup \{c |c \in DE',c$is a $commit\}$ - \EndFor - \State \Return{$ComSet$} -\EndFunction -\end{algorithmic} -\end{varwidth}% -} - -% Get all Transactions -\noindent\fbox{% -\begin{varwidth}{\dimexpr\linewidth-2\fboxsep-2\fboxrule\relax} -\textbf{Get all Transactions:}\\ -Get all transactions that are currently in the local block chain. Iterate over all the local slots and extract all the transactions from each slot.\\ -\begin{algorithmic}[1] -\Function{GetTrans}{$ $} - \State $TransSet \gets \emptyset$ \Comment{Set of the trans}\\ - - \LeftComment{Iterate over all the slots saved locally} - \ForAll{$\tuple{s_1', \tuple{seq_2',id',DE',hmac_p',hmac_c'}} \in LocalSlots$} - \State $TransSet \gets TransSet \cup \{c |c \in DE',c$is a $trans\}$ - \EndFor - \State \Return{$TransSet$} -\EndFunction -\end{algorithmic} -\end{varwidth}% -} - -% Get all aborts -\noindent\fbox{% -\begin{varwidth}{\dimexpr\linewidth-2\fboxsep-2\fboxrule\relax} -\textbf{Get all aborts:}\\ -Get all aborts that are currently in the local block chain. Iterate over all the local slots and extract all the aborts from each slot.\\ -\begin{algorithmic}[1] -\Function{GetAborts}{$ $} - \State $AbrtSet \gets \emptyset$ \Comment{Set of the aborts}\\ - - \LeftComment{Iterate over all the slots saved locally} - \ForAll{$\tuple{s_1', \tuple{seq_2',id',DE',hmac_p',hmac_c'}} \in LocalSlots$} - \State $AbrtSet \gets AbrtSet \cup \{c |c \in DE',c$is a $abort\}$ - \EndFor - \State \Return{$AbrtSet$} -\EndFunction -\end{algorithmic} -\end{varwidth}% -} - -% Get all Queue States -\noindent\fbox{% -\begin{varwidth}{\dimexpr\linewidth-2\fboxsep-2\fboxrule\relax} -\textbf{Get all queue states:}\\ -Get all qstates that are currently in the local block chain. Iterate over all the local slots and extract all the qstates from each slot.\\ -\begin{algorithmic}[1] -\Function{GetQStates}{$ $} - \State $QSet \gets \emptyset$ \Comment{Set of the qstates}\\ - - \LeftComment{Iterate over all the slots saved locally} - \ForAll{$\tuple{s_1', \tuple{seq_2',id',DE',hmac_p',hmac_c'}} \in LocalSlots$} - \State $QSet \gets QSet \cup \{c |c \in DE',c$is a $qstate\}$ - \EndFor - \State \Return{$QSet$} -\EndFunction -\end{algorithmic} -\end{varwidth}% -} - -% Get all Last Messages States -\noindent\fbox{% -\begin{varwidth}{\dimexpr\linewidth-2\fboxsep-2\fboxrule\relax} -\textbf{Get all last message data entrues:}\\ -Get all last msg that are currently in the local block chain. Iterate over all the local slots and extract all the last msg from each slot.\\ -\begin{algorithmic}[1] -\Function{GetLastMsg}{$ $} - \State $LMSet \gets \emptyset$ \Comment{Set of the last msg}\\ - - \LeftComment{Iterate over all the slots saved locally} - \ForAll{$\tuple{s_1', \tuple{seq_2',id',DE',hmac_p',hmac_c'}} \in LocalSlots$} - \State $LMSet \gets LMSet \cup \{c |c \in DE',c$is a $lastmsg\}$ - \EndFor - \State \Return{$LMSet$} -\EndFunction -\end{algorithmic} -\end{varwidth}% -} - -% Check Queue State Live -\noindent\fbox{% -\begin{varwidth}{\dimexpr\linewidth-2\fboxsep-2\fboxrule\relax} -\textbf{Check Queue State Live:}\\ -A queue state is dead if there is another queue state data entry that has a larger queue state.\\ -\begin{algorithmic}[1] -\Function{CheckQStateLive}{$qstate_a$} - \State $\tuple{size_a} \gets qstate_a$ - \State $AllQStates \gets$ \Call{GetQState}{} \Comment{Get all the qstates} \\ - - \If{$\exists \tuple{size'} \in AllQStates, size' > size_a$} - \State \Return{false} - \EndIf - \State \Return{true} - -\EndFunction -\end{algorithmic} -\end{varwidth}% -} - -% Check Commit Live -\noindent\fbox{% -\begin{varwidth}{\dimexpr\linewidth-2\fboxsep-2\fboxrule\relax} -\textbf{Check Commit Live:}\\ -A commit is dead if for every key value pair in the commit there is a commit with a larger transaction sequence number that has a key value pair with the same key.\\ -\begin{algorithmic}[1] -\Function{CheckCommitLive}{$commit_a$} - \State $\tuple{seq_{a_{trans}},KV_a} \gets commit_a$ - \State $KSet \gets \{k|\tuple{k,v} \in KV\}$ - \State $AllCommits \gets$ \Call{GetCommits}{} \Comment{Get all the commits} \\ - - \LeftComment{Iterate all commits that are newer in time} - \ForAll{$\tuple{seq_{trans}',KV'}\in AllCommits, seq_{trans}' > seq_{a_{trans}}$} - \State $KVSet \gets KVSet \setminus \{k|\tuple{k,v} \in KV'\}$\\ - - \If{$KVSet = \emptyset$} - \State \Return{false} \Comment{All keys have a newer commit} - \EndIf - \EndFor - \State \Return{true} \Comment{If got here then some keys still live} -\EndFunction -\end{algorithmic} -\end{varwidth}% -} - -% Check Last Message Live -\noindent\fbox{% -\begin{varwidth}{\dimexpr\linewidth-2\fboxsep-2\fboxrule\relax} -\textbf{Check Last Message Live:}\\ -The last message is dead if the device in question pushed a slot that has a larger sequence number than the one recorded in the last message data entry. \\ -\begin{algorithmic}[1] -\Function{CheckLastMsgLive}{$lastmsg_a$} - \State $\tuple{seq_a, id_a} \gets lastmsg_a$\\ - - \If{$\exists \tuple{id', seq'} \in LastSlot, id'=id_a \land seq' > seq_a$} - \State \Return{false} - \EndIf - \State \Return{True} -\EndFunction -\end{algorithmic} -\end{varwidth}% -} - -%Check Collision Resolution Live -\noindent\fbox{% -\begin{varwidth}{\dimexpr\linewidth-2\fboxsep-2\fboxrule\relax} -\textbf{Check Collision Resolution Live:}\\ -Check if a collision resolution data entry is live or not. This done by checking if all clients that we know about have seen the collision resolution entry. This is checked by seeing if all devices have inserted a message with a larger sequence number into the block chain.\\ -\begin{algorithmic}[1] -\Function{CheckColResLive}{$colres_a$} - \State $\tuple{id_a, seq_{a_{old}}, seq_{a_{new}}, equal_a} \gets colres_a$\\ - - \If{$\forall \tuple{id', seq'} \in LastSlot, seq' \geq seq_{a_{new}}$} - \State \Return{false} - \EndIf - \State \Return{true} -\EndFunction -\end{algorithmic} -\end{varwidth}% -} - -% Check New Key Live -\noindent\fbox{% -\begin{varwidth}{\dimexpr\linewidth-2\fboxsep-2\fboxrule\relax} -\textbf{Check New Key Live:}\\ -A new key data entry is always live.\\ -\begin{algorithmic}[1] -\Function{CheckNewkeyLive}{$newkey_a$} - \State \Return{True} -\EndFunction -\end{algorithmic} -\end{varwidth}% -} - -% Check Abort Live -\noindent\fbox{% -\begin{varwidth}{\dimexpr\linewidth-2\fboxsep-2\fboxrule\relax} -\textbf{Check Abort Live:}\\ -Check if an abort data entry is live or not. Abort is dead if the device whos transaction was aborted sees the abort. This is checked by seeing if that device inserted a slot into the block chain which has a sequence numberl that is larger than the aborts sequence number.\\ -\begin{algorithmic}[1] -\Function{CheckAbortLive}{$abort_a, seq_a$} - \State $\tuple{seq_{a_{trans}},id_a} \gets abort_a$\\ - - \LeftComment{The device whos transaction was aborted saw the abort} - \If{$\exists \tuple{id', seq'} \in LastSlot, id'=id_a \land seq' > seq_a$} - \State \Return{false} - \EndIf - \State \Return{True} -\EndFunction -\end{algorithmic} -\end{varwidth}% -} - -% Check Transaction Live -\noindent\fbox{% -\begin{varwidth}{\dimexpr\linewidth-2\fboxsep-2\fboxrule\relax} -\textbf{Check Transaction Live:}\\ -A transaction is dead if there is an abort for that transaction or if there is a commit for that a transaction that came after this transaction. Since transactions must be committed in order of there insertion, seeing a transaction that is committed and has a larger sequence number than the transaction in question means that the transaction in question was committed at some point.\\ -\begin{algorithmic}[1] -\Function{CheckTransLive}{$trans_a$} - \State $\tuple{seq_a, id_a, KV_a, Guard_a} \gets trans_a$ - \State $AllCommits \gets$ \Call{GetCommits}{} \Comment{Get all the commits} - \State $AllAborts \gets$ \Call{GetAborts}{} \Comment{Get all the aborts} \\ - - \If{$\exists \tuple{seq_{abrt}',seq_{trans}',id'} \in AllAborts, seq_{trans}' = seq_a$} - \State \Return{false} - \ElsIf{$\exists \tuple{seq_{trans}',KV'} \in AllCommits, seq_{trans}' \geq seq_a$} - \State \Return{false} - \EndIf - \State \Return{true} -\EndFunction -\end{algorithmic} -\end{varwidth}% -} - -% Check Live -\noindent\fbox{% -\begin{varwidth}{\dimexpr\linewidth-2\fboxsep-2\fboxrule\relax} -\textbf{Check Live:}\\ -Checks if a data entry is live based on its type.\\ -\begin{algorithmic}[1] -\Function{CheckLive}{$datentry, seq$} - \If{$datentry$ is a $commit$} - \State \Return{\Call{CheckCommitLive}{$datentry$}}\ - \ElsIf{$datentry$ is a $abort$} - \State \Return{\Call{CheckAbortLive}{$datentry, seq$}}\ - \ElsIf{$datentry$ is a $trans$} - \State \Return{\Call{CheckTransLive}{$datentry$}}\ - \ElsIf{$datentry$ is a $lastmsg$} - \State \Return{\Call{CheckLastMsgLive}{$datentry$}}\ - \ElsIf{$datentry$ is a $colres$} - \State \Return{\Call{CheckColResLive}{$datentry$}}\ - \ElsIf{$datentry$ is a $qstate$} - \State \Return{\Call{CheckQStateLive}{$datentry$}} - \ElsIf{$datentry$ is a $newkey$} - \State \Return{\Call{CheckNewkeyLive}{$datentry$}} - \Else - \State \Call{Error}{"Unknown data entry type."} - \EndIf -\EndFunction -\end{algorithmic} -\end{varwidth}% -} - -% Slot Has Live -\noindent\fbox{% -\begin{varwidth}{\dimexpr\linewidth-2\fboxsep-2\fboxrule\relax} -\textbf{Slot Has Live:}\\ -Check if the slot has any live data entries in it. Do this by looking at all the data entries in the slot and checking if they are live\\ -\begin{algorithmic}[1] -\Function{SlotHasLive}{$slot_a$} - \State $\tuple{s_1, \tuple{seq_2,id,DE,hmac_p,hmac_c}} \in LocalSlots$ - - \ForAll{$datentry \in DE$} - \If{\Call{CheckLive}{$datentry, s_1$}} \Comment{an entry is alive} - \State \Return{true} - \EndIf - \EndFor - - \State \Return{false} \Comment{All entries were dead} -\EndFunction -\end{algorithmic} -\end{varwidth}% -} - -% Calculate Resize Threshold -\noindent\fbox{% -\begin{varwidth}{\dimexpr\linewidth-2\fboxsep-2\fboxrule\relax} -\textbf{Calculate Resize Threshold:}\\ -Calculate a threshold for how many slots need to have live data entries in them for a resize to take place.\\ -\begin{algorithmic}[1] -\Function{CalcResizeThresh}{$maxsize$} - \State \Return{$\left \lfloor {maxsize * RESIZE\_THRESH\_PERCENT} \right \rfloor$} -\EndFunction -\end{algorithmic} -\end{varwidth}% -} - -% Calculate Block Chain New Size -\noindent\fbox{% -\begin{varwidth}{\dimexpr\linewidth-2\fboxsep-2\fboxrule\relax} -\textbf{Calculate Block Chain New Size:}\\ -Calculate the new size of the block chain which we need if we are to resize the data structure.\\ -\begin{algorithmic}[1] -\Function{CalcNewSize}{$maxsize$} - \State \Return{$\left \lceil {maxsize * RESIZE\_THRESH\_PERCENT} \right \rceil$} -\EndFunction -\end{algorithmic} -\end{varwidth}% -} - -% Should Resize -\noindent\fbox{% -\begin{varwidth}{\dimexpr\linewidth-2\fboxsep-2\fboxrule\relax} -\textbf{Should Resize:}\\ -Check if the block should resize based on some metric of how many slots in the block chain are filled with live data. \\ -\begin{algorithmic}[1] -\Function{ShouldResize}{$ $} - \State $LiveSlots \gets \{slot_s|slot_s \in LocalSlots \land $\Call{SlotHasLive}{$slot_s$}$\}$ - \State $resizethreshold \gets $ \Call{CalcResizeThresh}{$max\_size$} - \State \Return{$|LiveSlots| \geq resizethreshold$} \Comment{If passes threshold then resize} -\EndFunction -\end{algorithmic} -\end{varwidth}% -} - -% Create Queue State -\noindent\fbox{% -\begin{varwidth}{\dimexpr\linewidth-2\fboxsep-2\fboxrule\relax} -\textbf{Create Queue State:}\\ -Generate a queue state data entry.\\ -\begin{algorithmic}[1] -\Function{CreateQState}{$size_a$} - \State \Return{$\tuple{size_a}$} -\EndFunction -\end{algorithmic} -\end{varwidth}% -} - -% Create Abort -\noindent\fbox{% -\begin{varwidth}{\dimexpr\linewidth-2\fboxsep-2\fboxrule\relax} -\textbf{Create Abort:}\\ -Generate a abort data entry.\\ -\begin{algorithmic}[1] -\Function{CreateAbort}{$seq_a, id_a$} - \State \Return{$\tuple{seq_a, id_a}$} -\EndFunction -\end{algorithmic} -\end{varwidth}% -} - -% Create Collision -\noindent\fbox{% -\begin{varwidth}{\dimexpr\linewidth-2\fboxsep-2\fboxrule\relax} -\textbf{Create ColRes:}\\ -Generate a colres data entry.\\ -\begin{algorithmic}[1] -\Function{CreateColRes}{$is_a, seq_{a_{old}}, seq_{a_{new}}, isequal_a$} - \State \Return{$\tuple{id_a, seq_{a_{old}}, seq_{a_{new}},}isequal_a$} -\EndFunction -\end{algorithmic} -\end{varwidth}% -} - - -% Create Transaction -\noindent\fbox{% -\begin{varwidth}{\dimexpr\linewidth-2\fboxsep-2\fboxrule\relax} -\textbf{Create Transaction:}\\ -Generate a transaction data entry.\\ -\begin{algorithmic}[1] -\Function{CreateTrans}{$pendingtrans_a, seq_a$} - \State $\tuple{KV_a, Guard_a} \gets pendingtrans_a$ - \State \Return{$\tuple{seq_a, LOCAL\_ID, KV_a, Guard_a}$} -\EndFunction -\end{algorithmic} -\end{varwidth}% -} - -% Create Commit -\noindent\fbox{% -\begin{varwidth}{\dimexpr\linewidth-2\fboxsep-2\fboxrule\relax} -\textbf{Create Commit:}\\ -Generate a commit data entry.\\ -\begin{algorithmic}[1] -\Function{CreateCommit}{$seq_a,KV_a$} - \State \Return{$\tuple{seq_a,KV_a}$} -\EndFunction -\end{algorithmic} -\end{varwidth}% -} - -% Create New Key -\noindent\fbox{% -\begin{varwidth}{\dimexpr\linewidth-2\fboxsep-2\fboxrule\relax} -\textbf{Create New Key:}\\ -Generate a new key data entry.\\ -\begin{algorithmic}[1] -\Function{CreateNewKey}{$k_a, id_a$} - \State \Return{$\tuple{k_a,id_a}$} -\EndFunction -\end{algorithmic} -\end{varwidth}% -} - -% Data Entry Set Has Space -\noindent\fbox{% -\begin{varwidth}{\dimexpr\linewidth-2\fboxsep-2\fboxrule\relax} -\textbf{Data Entry Set Has Space :}\\ -Checks if a data entry set has enough space for a new data entry to be inserted.\\ -\begin{algorithmic}[1] -\Function{DEHasSpace}{$DE_a, de_a$} - \State $newsize \gets $ \Call{GetSize}{$DE_a$} - \State $newsize \gets newsize +$ \Call{GetSize}{$de_a$} - \State \Return{$newsize \leq DATA\_ENTRY\_SET\_MAX\_SIZE$} -\EndFunction -\end{algorithmic} -\end{varwidth}% -} - -% Create Rescued Commit -\noindent\fbox{% -\begin{varwidth}{\dimexpr\linewidth-2\fboxsep-2\fboxrule\relax} -\textbf{Create Rescued Date Entry:}\\ -For commits only the key-value pairs that are most recent (no newer commit that has those key values in it).\\ -\begin{algorithmic}[1] -\Function{CreateRescuedCommit}{$commit_a$} - \State $AllCommits \gets $ \Call{GetCommits}{} - \State $\tuple{seq_{a_{trans}},KV_a} \gets de_a$ - \State $NewKV \gets KV_a$\\ - - \LeftComment{Get rid of all key values that have newer commits} - \ForAll{$\tuple{k_a, v_a} \in KV_a$} - \LeftComment{Iterate over all commits that are newer than the rescue commit} - \ForAll{$\tuple{seq', KV'} \in AllCommits, seq' > seq_{a_{trans}}$} - \If{$\exists \tuple{k', v'} \in KV', k' = k_a$} - \State $NewKV \gets NewKV \setminus \tuple{k_a, v_a}$ - \State Break - \EndIf - \EndFor - \EndFor - \State \Return{$\tuple{seq_{a_{trans}}, NewKV}$} -\EndFunction -\end{algorithmic} -\end{varwidth}% -} - -% Create Rescued Date Entry -\noindent\fbox{% -\begin{varwidth}{\dimexpr\linewidth-2\fboxsep-2\fboxrule\relax} -\textbf{Create Rescued Date Entry:}\\ -Generate the data entry rescued version of the entry. For some data entry types such as commits, the entry is not rescued as is. For commits only the key-value pairs that are most recent (no newer commit that has those key values in it).\\ -\begin{algorithmic}[1] -\Function{CreateRescuedEntry}{$de_a$} - - \If{$de_a$is a $commit$} - \State \Return{\Call{CreateRescuedCommit}{$de_a$}} - \EndIf - - \State \Return{$de_a$} \Comment{No Modification needed} -\EndFunction -\end{algorithmic} -\end{varwidth}% -} - -% Check Slot Hmacs -\noindent\fbox{% -\begin{varwidth}{\dimexpr\linewidth-2\fboxsep-2\fboxrule\relax} -\textbf{Check Slot HMACs:}\\ -Check that each slot has not been tampered with by checking that the stored HMAC matches the calculated HMAC. Also check thatthe slot number reported by the server matches the slot number of the actual slot.\\ -\begin{algorithmic}[1] -\Function{CheckSlotsHmacAndSeq}{$Slots_a$} - \ForAll{$slot_a \in Slots_a$} - \State $\tuple{seq_{a_1}, \tuple{seq_{a_2},id_a,DE_a,hmac_{a_p},hmac_{a_c}}} \gets slot_a$ - \State $calchmac \gets $ \Call{GenerateHmac}{$seq_{a_2}, id_a, DE_a, hmac_{a_p}$} - - \If{$seq_{a_1} \neq seq_{a_2}$} - \State \Call{Error}{"Slot sequence number mismatch"} - \ElsIf{$calchmac \neq hmac_{a_c}$} - \State \Call{Error}{"Slot HMAC mismatch"} - \EndIf - \EndFor -\EndFunction -\end{algorithmic} -\end{varwidth}% -} - -% Check HMAC Chain -\noindent\fbox{% -\begin{varwidth}{\dimexpr\linewidth-2\fboxsep-2\fboxrule\relax} -\textbf{Check HMAC Chain:}\\ -Check that the HMAC chain has not been violated.\\ -\begin{algorithmic}[1] -\Function{CheckHmacChain}{$Slots_a$} - \State $SlotsList \gets Slots_a$ sorted by sequence number\\ - - - \LeftComment{Check all new slots} - \ForAll{$index \in [2: |SlotsList|]$} - \State $\tuple{seq_{a_1}, \tuple{seq_{a_2},id_a,DE_a,hmac_{a_p},hmac_{a_c}}} \gets SlotList[i-1]$ - \State $\tuple{seq_{b_1}, \tuple{seq_{b_2},id_b,DE_b,hmac_{b_p},hmac_{b_c}}} \gets SlotList[i]$ - - \If{$hmac_{b_p} \neq hmac_{b_c}$} - \State \Call{Error}{"Invalid previous HMAC."} - \EndIf - \EndFor\\ - - \LeftComment{Check against slots that we already have in the block chain} - \If{$|LocalSlots| \neq 0$} - \State $\tuple{seq, SDE} \gets $\Call{MaxSlot}{$LocalSlots$} - \State $\tuple{seq{last_2},id_{last},DE_{last},hmac_{last_p},hmac_{last_c}} \gets SDE$\\ - - \State $\tuple{seq_{a_1}, \tuple{seq_{a_2},id_a,DE_a,hmac_{a_p},hmac_{a_c}}} \gets SlotList[1]$\\ - - \If{$(seq_{last_2} + 1) = seq_{a_1}$} - \If{$hmac_{a_p} \neq hmac_{last_c}$} - \State \Call{Error}{"Invalid previous HMAC."} - \EndIf - \EndIf - \EndIf - -\EndFunction -\end{algorithmic} -\end{varwidth}% -} - - -% Check For Old Slots -\noindent\fbox{% -\begin{varwidth}{\dimexpr\linewidth-2\fboxsep-2\fboxrule\relax} -\textbf{Check For Old Slots:}\\ -Check if the slots are not new. Checks if the "new" slots are actually new or if they are older than the most recent slot that we have.\\ -\begin{algorithmic}[1] -\Function{CheckOldSlots}{$Slots_a$} - \State $\tuple{seq_{new}, Dat_{new}} \gets$ \Call{MinSlot }{$Slots_a$} \Comment{Get the oldest new slot} - \State $\tuple{seq_{local}, Dat_{local}} \gets$ \Call{MaxSlot }{$LocalSlots$} \Comment{Get the newest slot seen}\\ - - \If{$seq_{new} \leq seq_{local}$} \Comment{The slots were not newer than what was already seen} - \State \Call{Error}{"Server sent old slots."} - \EndIf\\ - - \LeftComment{Check if slots have the same sequence number but different data entries} - \ForAll{$\tuple{seq, Dat} \in Slots_a$} - \If{$\exists \tuple{seq', Dat'} \in (LocalSlots \cup Slots_a), seq'=seq \land Dat' \neq Dat$} - \State \Call{Error}{"Slot sequence number match but data does not"} - \EndIf - \EndFor - -\EndFunction -\end{algorithmic} -\end{varwidth}% -} - -% Get All Queue States with Sequence numbers -% \noindent\fbox{% -% \begin{varwidth}{\dimexpr\linewidth-2\fboxsep-2\fboxrule\relax} -% \textbf{Get All Queue States with Sequence numbers:}\\ -% Gets all the queue states with the sequence number of the slot that the queue state was inside. -% \begin{algorithmic}[1] -% \Function{GetQStateWithSeq}{$Slots_a$} -% \State $QSet \gets \emptyset$\\ - -% \ForAll{$\tuple{seq_1', \tuple{seq_2',id',DE',hmac_p', hmac_c'}} \in Slots_a$} -% \ForAll{$de' \in DE'$} -% \If{$de'$ is a $qstate$} -% \State $QSet \gets QSet \cup \{\tuple{seq_1', de'}\}$ -% \EndIf -% \EndFor -% \EndFor\\ - -% \State \Return{$QSet$} -% \EndFunction -% \end{algorithmic} -% \end{varwidth}% -% } - -% Get All Queue States -\noindent\fbox{% -\begin{varwidth}{\dimexpr\linewidth-2\fboxsep-2\fboxrule\relax} -\textbf{Get All Queue States:}\\ -Gets all the queue states from the slots that were passed in.\\ -\begin{algorithmic}[1] -\Function{GetQState}{$Slots_a$} - \State $QSet \gets \emptyset$\\ - - \ForAll{$\tuple{seq_1', \tuple{seq_2',id',DE',hmac_p', hmac_c'}} \in Slots_a$} - \ForAll{$de' \in DE'$} - \If{$de'$ is a $qstate$} - \State $QSet \gets QSet \cup \{de'\}$ - \EndIf - \EndFor - \EndFor\\ - - \State \Return{$QSet$} -\EndFunction -\end{algorithmic} -\end{varwidth}% -} - - -% Check Size With Gap -\noindent\fbox{% -\begin{varwidth}{\dimexpr\linewidth-2\fboxsep-2\fboxrule\relax} -\textbf{Check Size With Gap:}\\ -Checks that the block chain size is correct when there is a gap in the block chain. This check makes sure that the server is not hiding any information from the client. If there is a gap and there is only 1 queue state in the new slot entries then there must have at least that many slots since the old slot entry must have been purged. If there is more than 1 queue state then the block chain is still growing check the smallest max size and there should be at least that many slots. \\ -\begin{algorithmic}[1] -\Function{CheckSizeWithGap}{$Slots_a$} - %\State $QSSet \gets $ \Call{GetQStateWithSeq}{$Slots_a$} - %\State $\tuple{seq_{max}, size_{max}} \gets \tuple{seq, size}$ such that $\tuple{seq, size} \in QSSet \land \forall \tuple{seq', size'} \in QSSet, size \geq size'$ \Comment{Get largest size} - %\State $\tuple{seq_{min}, size_{min}} \gets \tuple{seq, size}$ such that $\tuple{seq, size} \in QSSet \land \forall \tuple{seq', size'} \in QSSet , size \leq size'$ \Comment{Get smallest size} - - \State $QSet \gets $ \Call{GetQState}{$Slots_a$} - \State $size_{max} \gets size$ such that $size \in QSet \land \forall size' \in QSet, size \geq size'$ - \State $size_{min} \gets size$ such that $size \in QSet \land \forall size' \in QSet, size \leq size'$ - \State $Slots_{oldmax} \gets \emptyset$\\ - - - \LeftComment{If only 1 max size then we must have all the slots for that size} - \If{$(|QSSet| = 1) \land (|Slots_a| \neq size_{max})$} - \State \Call{Error}{"Missing Slots"} - \EndIf\\ - - \LeftComment{We definitely have all the slots} - \If$|Slots_a| = size_{max}$ - \State \Return{} \Comment{We have all the slots} - \EndIf\\ - - \LeftComment{We must have at least this many slots} - \If$|Slots_a| < size_{min}$ - \State \Call{Error}{"Missing Slots"} - \EndIf\\ - -\EndFunction -\end{algorithmic} -\end{varwidth}% -} - -% Check Size -\noindent\fbox{% -\begin{varwidth}{\dimexpr\linewidth-2\fboxsep-2\fboxrule\relax} -\textbf{Check Size:}\\ -\begin{algorithmic}[1] -\Function{CheckSize}{$Slots_a$} - \State $\tuple{seq_{old_{max}}, Dat_{old_{max}}} \gets $ \Call{MaxSlot}{$LocalSlots$} - \State $\tuple{seq_{new_{max}}, Dat_{new_{max}}} \gets $ \Call{MinSlot}{$Slots_a$}\\ - - \If{$(seq_{old_{max}} + 1) = seq_{new_{max}}$} - \LeftComment{No Gap so cannot say anything about the size} - \State \Return{} - \Else - \LeftComment{Has a gap so we need to do checks} - \State \Call{CheckSizeWithGap}{$Slots_a$} - \EndIf -\EndFunction -\end{algorithmic} -\end{varwidth}% -} - - -% % Initialize the expected size of the block chain -% \noindent\fbox{% -% \begin{varwidth}{\dimexpr\linewidth-2\fboxsep-2\fboxrule\relax} -% \textbf{Initialize the expected size of the block chain:}\\ -% Initialize the expected size of the block chain based on the size at the server.\\ -% \begin{algorithmic}[1] -% \Function{InitExpSize}{$seq_a$} -% \State $startingsize \gets 0$\\ - -% \If{$seq_a < max\_size$} \Comment{Check whether saves slots are full on server} -% \State $startingsize \gets seq_a$ -% \Else -% \State $startingsize \gets max\_size$ -% \EndIf\\ - -% \State \Return{$startingsize$} -% \EndFunction -% \end{algorithmic} -% \end{varwidth}% -% } - -% % Update the expected size of the block chain -% \noindent\fbox{% -% \begin{varwidth}{\dimexpr\linewidth-2\fboxsep-2\fboxrule\relax} -% \textbf{Update the expected size of the block chain:}\\ -% Update the expected size of the block chain.\\ -% \begin{algorithmic}[1] -% \Function{UpdateExpSize}{$size_a$} -% \State $size_a \gets size_a + 1$\\ - -% \If{$size_a > max\_size$}\Comment{Expected size $\leq max\_size$} -% \State $ssize_a \gets max_\_size$ -% \EndIf\\ - -% \State \Return{$size_a$} -% \EndFunction -% \end{algorithmic} -% \end{varwidth}% -% } - - - -% Update Last Message -\noindent\fbox{% -\begin{varwidth}{\dimexpr\linewidth-2\fboxsep-2\fboxrule\relax} -\textbf{Process Commit Data Entry:}\\ -Process a commit entry. Updates the local copy of commits.\\ -\begin{algorithmic}[1] -\Function{UpdateLastMessage}{$seq_a, id_a, LstSlt_a, updateinglocal_a$} - \State $\tuple{id_{old}, seq_{old}} \gets \tuple{id', seq'}$ such that $\tuple{id', seq'} \in LastSlot \land id'=id$\\ - - \If{$id_a = LOCAL\_ID$} - \If{$\lnot updateinglocal_a \land (seq_a \neq seq_{old})$} - \LeftComment{This client did not make any updates so its latest sequence number should not change} - \State \Call{Error}{"Mismatch on local machine sequence number"} - \EndIf - \Else - \If{$seq_{old} > seq_a$} - \State \Call{Error}{"Rollback on remote machine sequence number"} - \EndIf - \EndIf\\ - - \State $LastSlot \gets LastSlot \setminus \{\tuple{id, seq} | \tuple{id, seq} \in LastSlot, id=id_a\}$ - \State $LastSlot \gets LastSlot \cup \{\tuple{id_a, seq_a}\}$ - - \State \Return{$LstSlt_a \setminus \{\tuple{id, seq} | \tuple{id, seq} \in LstSlt_a, id=id_a\}$} -\EndFunction -\end{algorithmic} -\end{varwidth}% -} - -% Process Commit Data Entry -\noindent\fbox{% -\begin{varwidth}{\dimexpr\linewidth-2\fboxsep-2\fboxrule\relax} -\textbf{Process Commit Data Entry:}\\ -Process a commit entry. Updates the local copy of commits.\\ -\begin{algorithmic}[1] -\Function{ProcessCommit}{$commit_a$} - \State $\tuple{seq_{a_{trans}},KV_a} \gets commit_a$ - \State $DKV \gets \{\tuple{k,v}| \tuple{k,v} \in CommittedKV \land \tuple{k',v'}\in KV_a \land k'=k\}$ - \State $CommittedKV \gets (CommittedKV \setminus DKV) \cup KV_a$ -\EndFunction -\end{algorithmic} -\end{varwidth}% -} - -% Process Queue State Data Entry -\noindent\fbox{% -\begin{varwidth}{\dimexpr\linewidth-2\fboxsep-2\fboxrule\relax} -\textbf{Process Queue State Entry:}\\ -Process a queue state entry. Updates the max size of the block chain\\ -\begin{algorithmic}[1] -\Function{ProcessQState}{$qstate_a$} - \State $\tuple{size_a} \gets qstate_a$ - \State $max\_size \gets size_a$ \Comment{Update the max size we can have} -\EndFunction -\end{algorithmic} -\end{varwidth}% -} - -% Process Collision Resolution Entry -\noindent\fbox{% -\begin{varwidth}{\dimexpr\linewidth-2\fboxsep-2\fboxrule\relax} -\textbf{Process Queue State Entry:}\\ -Process a collision resolution entry.\\ -\begin{algorithmic}[1] -\Function{ProcessColres}{$colres_a, NewSlots_a$} - \State $\tuple{id_a, seq_{a_{old}}, seq_{a_{new}}, isequal_a}$ - \State $AllSlots \gets LocalSlots \cup NewSlots_a$ - \State $index \gets seq_{a_{old}}$\\ - - \While{$index <= seq_{a_{new}}$} - \State $slt \gets \tuple{seq' Dat'}$ such that $\tuple{seq' Dat'} \in AllSlots \land seq'=index$ - - \If{$\exists \tuple{seq' Dat'} \in AllSlots, seq' = index$} - \State $\tuple{seq, Dat} \gets \tuple{seq' Dat'}$ such that $\tuple{seq' Dat'} \in AllSlots \land seq'=index$ - \State $\tuple{seq,id,DE,hmac_p,hmac_c} \gets Dat$ - \If{$isequal_a \neq (id=id_a)$} - \State \Call{Error}{"Trying to insert rejected messages for slot"} - \EndIf - \EndIf\\ - \State $index \gets index + 1$ - \EndWhile - - -\EndFunction -\end{algorithmic} -\end{varwidth}% -} - -% Process New Key Data Entry -\noindent\fbox{% -\begin{varwidth}{\dimexpr\linewidth-2\fboxsep-2\fboxrule\relax} -\textbf{Process New Key Entry:}\\ -Process a queue state entry. Adds a key to the key arbitrator set\\ -\begin{algorithmic}[1] -\Function{ProcessNewkey}{$newkey_a$} - \State $\tuple{seq_a, k_a, id_a} \gets newkey_a$ - \State $Arbitrator \gets Arbitrator \cup \{\tuple{k_a,id_a}\}$ -\EndFunction -\end{algorithmic} -\end{varwidth}% -} - -% Process Process Data Entry -\noindent\fbox{% -\begin{varwidth}{\dimexpr\linewidth-2\fboxsep-2\fboxrule\relax} -\textbf{Process Data Entry:}\\ -Process the data entry based on what kind of entry it is.\\ -\begin{algorithmic}[1] -\Function{ProcessDatEntry}{$slot_a, NewSlots_a,LstSlt_a$} - \If{$datentry_a$ is a $commit$} - \State \Call{ProcessCommit}{$dataentry_a$} - - \ElsIf{$datentry_a$ is a $abort$} - \LeftComment{Do Nothing in this case} - - \ElsIf{$datentry_a$ is a $trans$} - \LeftComment{Do Nothing in this case} - - \ElsIf{$datentry_a$ is a $lastmsg$} - \State $\tuple{seq_a, id_a} \gets dataentry_a$ - \State $LstSlt_a \gets$ \Call{UpdateLastMessage}{$seq_a, id_a, LstSlt_a, false$} - - \ElsIf{$datentry_a$ is a $colres$} - \State \Call{ProcessColres}{$dataentry_a, NewSlots_a$} - - \ElsIf{$datentry_a$ is a $qstate$} - \State \Call{ProcessQState}{$dataentry_a$} - - \ElsIf{$datentry_a$ is a $newkey$} - \State \Call{ProcessNewkey}{$dataentry_a$} - - \Else - \State \Call{Error}{"Unknown data entry type."} - \EndIf - - \State \Return{$LstSlt_a$} -\EndFunction -\end{algorithmic} -\end{varwidth}% -} - - -% Delete Local Slots -\noindent\fbox{% -\begin{varwidth}{\dimexpr\linewidth-2\fboxsep-2\fboxrule\relax} -\textbf{Delete Local Slots:}\\ -Deletes local slots that are deleted at the server. This keeps the size of the local block chain bounded.\\ -\begin{algorithmic}[1] -\Function{DeleteLocalSlots}{$ $} - \State $\tuple{seq_{max}, Dat_{max}} \gets $ \Call{MaxSlot}{$LocalSlots$} - \State $seq_{min} \gets seq_{max} - max\_size$ \Comment{Min sequence number we should keep} - \State $LSDelete \gets \emptyset$ - - \If{$|LocalSlots| \leq max\_size$} - \State \Return{} \Comment{Nothing to delete} - \EndIf\\ - - \State $LSDelete \gets \{\tuple{seq', Dat'}|\tuple{seq', Dat'} \in LocalSlots, seq' > seq_{min}\}$ - \State $LocalSlots \gets LocalSlots \setminus LSDelete$ -\EndFunction -\end{algorithmic} -\end{varwidth}% -} - -% Create Speculative KV -\noindent\fbox{% -\begin{varwidth}{\dimexpr\linewidth-2\fboxsep-2\fboxrule\relax} -\textbf{Create Speculative KV:}\\ -Speculates on what the most recent key value pairs will be based on the latest committed key value pairs and the uncommitted transactions.\\ -\begin{algorithmic}[1] -\Function{SpeculateKV}{$ $} - \State $AllTrans \gets$ \Call{GetTrans}{} - \State $LiveTrans \gets \{t| t\in AllTrans, $\Call{CheckTransLive}{$t$}$\}$ - \State $CurrKV \gets CommittedKV$ - \State $DKV \gets \emptyset$ - - \ForAll{$\tuple{seq_t, id_t, KV_t, Guard_t} \in LiveTrans$ ordered by $seq'$} - \If{\Call{EvaluateGuard}{$Guard_t, CurrKV$}} - \State $DKV \gets \{\tuple{k,v}| \tuple{k,v} \in CurrKV \land \tuple{k',v'}\in KV_t \land k'=k\}$ - \State $CurrKV \gets (CurrKV \setminus DKV) \cup KV_t$ - \EndIf - \EndFor - - \State \Return{$CurrKV$} -\EndFunction -\end{algorithmic} -\end{varwidth}% -} - - -% Validate and Update -\noindent\fbox{% -\begin{varwidth}{\dimexpr\linewidth-2\fboxsep-2\fboxrule\relax} -\textbf{Validate Update:}\\ -Validate the block chain and insert into the local block chain.\\ -\begin{algorithmic}[1] -\Function{ValidateUpdate}{$NewSlots_a, updatinglocal_a$} - \State $\tuple{seq_{oldest}, Dat_{oldest}} \gets$ \Call{MinSlot}{$NewSlots_a$} - \State $\tuple{seq_{newest}, Dat_{newest}} \gets$ \Call{MaxSlot}{$NewSlots_a$} - \State $\tuple{seq_{local}, Dat_{local}} \gets$ \Call{MaxSlot}{$LocalSlots$} - \State $LastSlotTmp \gets LastSlot$\\ - %\State $currsize \gets $\Call{InitExpSize}{$seq_{oldest}$}\\ - - \State \Call{CheckSlotsHmacAndSeq}{$NewSlots_a$} \Comment{Check all the HMACs} - \State \Call{CheckHmacChain}{$NewSlots_a$} \Comment{Check HMAC Chain} - \State \Call{CheckOldSlots}{$NewSlots_a$} \Comment{Check if new slots are actually old slots} - \State \Call{CheckSize}{$NewSlots_a$} \Comment{Check if the size is correct}\\ - - \ForAll{$slot_a \in NewSlots_a$ in order of sequence number} - \If{$slot_a \in LocalSlots$} \Comment{Client already has this slot} - \State $NewSlots_a \gets NewSlots_a \setminus \{slot_a\}$ - \State Continue - \EndIf\\ - - \State $\tuple{seq_{a_1}, \tuple{seq_{a_2},id_a,DE_a,hmac_{a_p},hmac_{a_c}}} \gets slot_a$ - \State $LstSlt_a \gets$ \Call{UpdateLastMessage}{$seq_{a_1}, id_a, LstSlt_a, updatinglocal_a$}\\ - - \ForAll{$de_a \in DE_a$} \Comment{Process each data entry} - \State $LstSlt_a \gets $ \Call{ProccessDatEntry}{$de_a, NewSlots_a,LstSlt_a$} - \EndFor\\ - - %\State $currsize \gets $ \Call{UpdateExpSize}{$currsize$}\\ - \State $LocalSlots \gets LocalSlots \cup \{slot_a\}$ \Comment{Add to local Chain} - \EndFor\\ - - \If{$seq_{oldest} > (seq_{local} +1) \land LastSlotTmp \neq \emptyset$} - \LeftComment{There was a gap so there should be a complete set of information on each previously seen client} - \State \Call{Error}{"Missing records for machines"} - \EndIf\\ - - \State \Call{DeleteLocalSlots}{ } \Comment{Delete old slots from local} - \State $SpeculatedKV \gets $\Call{SpeculateKV}{ } \Comment{Speculate on what will be latest KV set} - -\EndFunction -\end{algorithmic} -\end{varwidth}% -} - -% Decrypt Validate Insert Slots -\noindent\fbox{% -\begin{varwidth}{\dimexpr\linewidth-2\fboxsep-2\fboxrule\relax} -\textbf{Decrypt Validate Insert Slots:}\\ -Decrypts slots, validates (checks for malicious activity) slots and inserts the slots into the local block chain.\\ -\begin{algorithmic}[1] -\Function{DecryptValidateInsert}{$NewSlots_a, updatinglocal_a$} - \State $DecryptedSlots \gets \emptyset$ - \State $DDat \gets NULL$\\ - - \ForAll{$\tuple{seq', EDat'} \in NewSlots_a$} - \State $DDat \gets $ \Call{Decrypt}{$EDat'$} - \State $DecryptedSlots \gets DecryptedSlots \cup \tuple{seq',DDat}$ - \EndFor\\ - \State \Call{ValidateUpdate}{$DecryptedSlots, updatinglocal_a$} -\EndFunction -\end{algorithmic} -\end{varwidth}% -} - -% Check and Create Last Message Data Entry -\noindent\fbox{% -\begin{varwidth}{\dimexpr\linewidth-2\fboxsep-2\fboxrule\relax} -\textbf{Check and Create Last Message Data Entry:}\\ -Check if a last message entry needs to be created for this slot and if so create it. The check is done by checking if there are any newer slots with the same id or if there is already a last message slot with a newer sequence number\\ -\begin{algorithmic}[1] -\Function{CheckCreateLastMsgEntry}{$seq_a, id_a$} - \State $AllLastMsg \gets$ \Call{GetLastMsg}{}\\ - - \LeftComment{Already Has one} - \If{$\exists \tuple{seq', id'} \in AllLastMsg, id_a=id' \land seq'=seq_a$} - \State \Return{$\{\}$}\\ - \EndIf\\ - - \LeftComment{Not latest slot from that client} - \If{$\exists \tuple{seq_1', \tuple{seq_2',id',DE',hmac_p',hmac_c'}} \in LocalSlots, id_a=id' \land seq_1'>seq_a$} - \State \Return{$\{\}$}\\ - \EndIf\\ - - - \State \Return{$\{\tuple{seq_a, id_a}\}$} -\EndFunction -\end{algorithmic} -\end{varwidth}% -} - -% Mandatory Rescue -\noindent\fbox{% -\begin{varwidth}{\dimexpr\linewidth-2\fboxsep-2\fboxrule\relax} -\textbf{Mandatory Rescue:}\\ -This rescue is mandatory before any types of data entries (excpet queue states) can be placed into the data entry section of the new slot. Returns the data entry Set or null if the first slot could not be cleared (the live data in that slot could not fit in this current slot). \\ -\begin{algorithmic}[1] -\Function{MandatoryRescue}{$DE_a$} - \State $smallestseq \gets seq$ such that $\tuple{seq, DE}\in LocalSlots \land (\forall \tuple{seq', DE'} \in LocalSlots, seq \leq seq')$ - \State $cseq \gets smallestseq$\\ - - \LeftComment{Check the least slots to rescue and live entries} - \While{$cseq < (smallestseq + DEAD\_SLOT\_COUNT)$} - \State $currentslot \gets s'$ such that $\tuple{s',DE'} \in LocalSlots \land s' = cseq$ - \State $\tuple{seq', \tuple{seq_2',id',DE',hmac_p',hmac_c'}} \gets currentslot$ - \State $DE' \gets DE' \cup$ \Call{CheckCreateLastMsgEntry}{$seq', id'$} \Comment{Get the last message too if we need it}\\ - - \ForAll{$de \in DE'$} \Comment{Iterate over all the entries} - \If{\Call{CheckLive}{$de, cseq$}} \Comment{data entry is live} - \State $de \gets $ \Call{CreateRescuedEntry}{de} \Comment{Resize entry if needed} - \If{\Call{DEHasSpace}{$DE_a, de$}} - \State $DE_a \gets DE_a \cup de$ \Comment{Had enough space to add it} - \ElsIf{$currentseq = smallestseq$} - \State \Return{$NULL$} - \Else - \State \Return{$DE_a$} - \EndIf - \EndIf - \EndFor\\ - - \State $cseq \gets cseq+1$ \Comment{Move onto the next slot} - \EndWhile - - \State \Return{$DE_a$} -\EndFunction -\end{algorithmic} -\end{varwidth}% -} - -% Optional Rescue -\noindent\fbox{% -\begin{varwidth}{\dimexpr\linewidth-2\fboxsep-2\fboxrule\relax} -\textbf{Optional Rescue:}\\ -This rescue is not mandatory. This is trying to fill the remaining portion of the slot with rescued data so that no space is wasted. If we encounter a data entry that does not fit move on to the next, maybe that one will fit. Do this until we skipped too many live data entries\\ -\begin{algorithmic}[1] -\Function{OptionalRescue}{$DE_a$} - \State $smallestseq \gets seq$ such that $\tuple{seq, DE}\in LocalSlots \land (\forall \tuple{seq', DE'} \in LocalSlots, seq \leq seq')$ - \State $largestseq \gets seq$ such that $\tuple{seq, DE}\in LocalSlots \land (\forall \tuple{seq', DE'} \in LocalSlots, seq \geq seq')$ - - \State $numofskips \gets 0$ - \State $cseq \gets smallestseq$\\ - - \LeftComment{Check the least slots to rescue and live entries} - \While{$cseq < largestseq$} - \State $currentslot \gets s'$ such that $\tuple{s',DE'} \in LocalSlots \land s' = cseq$ - \State $\tuple{seq', \tuple{seq_2',id',DE',hmac_p',hmac_c'}} \gets currentslot$\\ - - \ForAll{$de \in DE'$} \Comment{Iterate over all the entries} - \If{\Call{CheckLive}{$de, cseq$}} \Comment{data entry is live} - \State $de \gets $ \Call{CreateRescuedEntry}{de} \Comment{Resize entry if needed}\\ - - \If{$de \in DE_a$} \Comment{Already being rescued} - \State Continue - \EndIf\\ - - \If{\Call{DEHasSpace}{$DE_a, de$}} - \State $DE_a \gets DE_a \cup de$ \Comment{Had enoug space to add it} - \ElsIf{$numofskips \geq MAX\_RESCUE\_SKIPS$} - \State \Return{$DE_a$} - \Else - $numofskips \gets numofskips +1$ - \EndIf - \EndIf - \EndFor\\ - - \State $cseq \gets cseq+1$ \Comment{Move onto the next slot} - \EndWhile - - \State \Return{$DE_a$} -\EndFunction -\end{algorithmic} -\end{varwidth}% -} - - -% Rejected Messages -\noindent\fbox{% -\begin{varwidth}{\dimexpr\linewidth-2\fboxsep-2\fboxrule\relax} -\textbf{Rejected Messages:}\\ -\begin{algorithmic}[1] -\Function{RejectedMessages}{$DE_a$} - \State $seq_{old} \gets seq$ such that $\tuple{seq} \in RejectedSlotList \land \forall \tuple{seq'} \in RejectedSlotList, seq \geq seq'$ - \State $prev \gets -1$\\ - - - - \If{$|RejectedSlotList| \geq REJECTED\_THRESH$} - \State $seq_{new} \gets seq$ such that $\tuple{seq} \in RejectedSlotList \land \forall \tuple{seq'} \in RejectedSlotList, seq \leq seq'$\\ - \State $colres \gets $ \Call{CreateColRes}{$LOCAL\_ID, seq_{old}, seq_{new}, false$} - \State \Return{$DE_a \cup \{colres\}$} - \EndIf\\ - - \ForAll{$\tuple{seq} \in RejectedSlotList$ sorted by $seq$} - \If{$\exists \tuple{seq',Dat'} \in LocalSlots$} - \State Break - \EndIf - \State $prev \gets seq$ - \EndFor\\ - - \If{$prev \neq -1$} - \State $DE_a \gets DE_a \cup$ \Call{CreateColRes}{$LOCAL\_ID, seq_{old}, prev, false$} - \EndIf\\ - - \State $RejectedSlotList \gets \{\tuple{seq}| \tuple{seq} \in RejectedSlotList, seq > prev\}$\\ - - \ForAll{$\tuple{seq} \in RejectedSlotList$ sorted by $seq$} - \State $DE_a \gets DE_a \cup$ \Call{CreateColRes}{$LOCAL\_ID, seq,seq, false$} - \EndFor\\ - - \State \Return{$DE_a$} -\EndFunction -\end{algorithmic} -\end{varwidth}% -} - - - -% Arbitrate -\noindent\fbox{% -\begin{varwidth}{\dimexpr\linewidth-2\fboxsep-2\fboxrule\relax} -\textbf{Arbitrate:}\\ -\begin{algorithmic}[1] -\Function{Arbitrate}{$DE_a$} - \State $AllCommits \gets$ \Call{GetCommits}{} - \State $AllTrans \gets$ \Call{GetTrans}{} - \State $LiveCommits \gets \{c| c\in AllCommits, $\Call{CheckCommitLive}{$c$}$\}$ - \State $LiveTrans \gets \{t| t\in AllTrans, $\Call{CheckTransLive}{$t$}$\}$ - \State $KV \gets \emptyset$ - \State $lastcomseq \gets -1$ - \State $CurrKV \gets \emptyset$ - \State $DKV \gets \emptyset$ - \State $KVTmp \gets \emptyset$\\ - - \LeftComment{Get all the latest commits} - \ForAll{$\tuple{seq_{trans}',KV'} \in LiveCommits$} - \State $CurrKV \gets CurrKV \cup KV'$ - \EndFor\\ - - \ForAll{$\tuple{seq_t, id_t, KV_t, Guard_t} \in LiveTrans$ ordered by $seq'$} - \If{\Call{GetArbitratorKV}{$KV_t$} $\neq LOCAL\_ID$} - \State Continue \Comment{Client not arbitrator for this transaction} - \EndIf\\ - - \If{$\lnot$\Call{EvaluateGuard}{$Guard_t, CurrKV$}} - \State $abortde \gets $\Call{CreateAbort}{$seq_t, id_t$} - \LeftComment{No more space so we cant arbitrate any further} - \If($lnot$\Call{DeHasSpace}{$DE_a, abortde$}) - \State \Return{$DE_a$} - \EndIf - \State $DE_a \gets DE_a \cup abortde$ - \Else - \State $DKV \gets \{\tuple{k,v}| \tuple{k,v} \in KV \land \tuple{k',v'}\in KV_t \land k'=k\}$ - \State $KVTmp \gets (KV \setminus DKV) \cup KV'$ - \State $DKV \gets \{\tuple{k,v}| \tuple{k,v} \in CurrKV \land \tuple{k',v'}\in KVTmp \land k'=k\}$ - \State $CurrKV \gets (CurrKV \setminus DKV) \cup KVTmp$ - \State $commitde \gets $ \Call{CreateCommit}{$seq_t,KVTmp$} - - \If{$\lnot$ \Call{DeHasSpace}{$DE_a, commitde$}} - \If{$lastcomseq \neq -1$} - \State $DE_a \gets DE_a \cup$ \Call{CreateCommit}{$lastcomseq,KV$} - \EndIf - \State \Return{$DE_a$} - \Else - \State $KV \gets KVTmp$ - \State $lastcomseq \gets seq_t$ - \EndIf - \EndIf - \EndFor - - \State $DE_a \gets DE_a \cup$ \Call{CreateCommit}{$lastcomseq,KV$} - \State \Return{$DE_a$} - - -\EndFunction -\end{algorithmic} -\end{varwidth}% -} - -% Create New Slot -\noindent\fbox{% -\begin{varwidth}{\dimexpr\linewidth-2\fboxsep-2\fboxrule\relax} -\textbf{Create New Slot:}\\ -Create a slot and encrypt it.\\ -\begin{algorithmic}[1] -\Function{CreateNewSlot}{$seq_a, DE_a$} - \State $\tuple{seq, SDE} \gets \tuple{seq', SDE'}$ such that $\tuple{seq', SDE'}\in LocalSlots \land (\forall \tuple{seq'', DE''} \in LocalSlots, seq' \geq seq'')$ - \State $\tuple{seq,id,DE,hmac_p,hmac_c} \gets SDE$\\ - - \State $newhmac \gets $ \Call{GenerateHmac}{$seq_a, LOCAL\_ID, DE_a, hmac_p$} - \State $newSDE \gets \tuple{seq,LOCAL\_ID,DE_a,hmac_c,newhmac}$ - \State $encryptnewSDE \gets $\Call{Encrypt}{newSDE}\\ - - \State \Return{$\tuple{seq_a, encryptnewSDE}$} -\EndFunction -\end{algorithmic} -\end{varwidth}% -} - -% Send Data to Server -\noindent\fbox{% -\begin{varwidth}{\dimexpr\linewidth-2\fboxsep-2\fboxrule\relax} -\textbf{Send Data to Server:}\\ -Send the data to the server. If this fails then new slots will be returned by the server.\\ -\begin{algorithmic}[1] -\Function{SendToServer}{$seq_a, DE_a, newsize_a$} - \LeftComment{Make the slot and try to send to server} - \State $newslot \gets $ \Call{CreateNewSlot}{$seq_a, DE_a$} - \State $\tuple{success, newslots} \gets$ \Call{PutSlot}{$seq_a, newslot, newsize_a$}\\ - - \If{$success$} - \State $RejectedSlotList \gets \emptyset$ - \State \Return{$\tuple{true, \{newslot\}}$} - \Else - \If{$|newslots| = 0$} - \State \Call{Error}{"Server rejected but did not send any slots"} - \EndIf - \State $RejectedSlotList \gets RejectedSlotList \cup \{seq_a\}$ - \State \Return{$\tuple{false, newslots}$} - \EndIf\\ -\EndFunction -\end{algorithmic} -\end{varwidth}% -} - - -% Try Insert Transaction -\noindent\fbox{% -\begin{varwidth}{\dimexpr\linewidth-2\fboxsep-2\fboxrule\relax} -\textbf{Try Insert Transaction:}\\ -Try to insert a transaction into the block chain. Does resizing, rescues and insertion of other data entry types as needed. \\ -\begin{algorithmic}[1] -\Function{TryInsertTransaction}{$pendingtrans_a, forceresize$} - \State $DE \gets \emptyset$ \Comment{The data entries for this slot} - \State $seq \gets $ \Call{GetNextSeq}{} \Comment{Get the sequence number for this slot} - \State $newsize \gets 0$ - \State $trans \gets$ \Call{CreateTrans}{$pendingtrans_a, seq$} - \State $transinserted \gets false$ - \State $slotstoinsert \gets \emptyset$\\ - - \State $resize \gets $ \Call{ShouldResize}{ } \Comment{Check if we should resize} - \State $resize \gets resize \lor forceresize$ - \If{$resize$} - \State $newsize \gets$ \Call{CalcNewSize}{$max\_size$} - \State $DE \gets DE \cup \{$\Call{CreateQState}{$newsize$}$\}$ - \EndIf\\ - - \If{$RejectedSlotList \neq \emptyset$} - \State $DE \gets$ \Call{RejectedMessages}{$DE$} - \EndIf\\ - - \State $DE \gets$ \Call{MandatoryRescue}{$DE$} \Comment{Round 1 of rescue} - \If{$DE = NULL$} - \LeftComment{Data was going to fall off the end so try again with a forced resize} - \State \Return{\Call{TryInsertTransaction}{$trans_a, true$}} - \EndIf\\ - - \State $DE \gets $\Call{Arbitrate}{$DE$}\\ - - \If{\Call{DEHasSpace}{$DE, trans$}} \Comment{transaction fits} - \State $DE \gets DE \cup trans$ - \State $transinserted \gets true$ - \EndIf\\ - - \LeftComment{Rescue data to fill slot data entry section} - \State $DE \gets$ \Call{OptionalRescue}{$DE$}\\ - - \LeftComment{Send to server.} - \State $\tuple{sendsuccess, newslots} \gets $ \Call{SendToServer}{$seq, DE, newsize$}\\ - - \LeftComment{Insert the slots into the local bloakc chain} - \State \Call{DecryptValidateInsert}{$newslots, true$}\\ - - \State \Return{$transinserted \land success$} \Comment{Return if succeeded or not} - -\EndFunction -\end{algorithmic} -\end{varwidth}% -} - - -% Try Insert New Key -\noindent\fbox{% -\begin{varwidth}{\dimexpr\linewidth-2\fboxsep-2\fboxrule\relax} -\textbf{Try Insert New Key:}\\ -Try to insert a new key into the block chain. Does resizing, rescues and insertion of other data entry types as needed. \\ -\begin{algorithmic}[1] -\Function{TryInsertNewKey}{$k_a, id_a, forceresize$} - \State $DE \gets \emptyset$ \Comment{The data entries for this slot} - \State $seq \gets $ \Call{GetNextSeq}{} \Comment{Get the sequence number for this slot} - \State $newsize \gets 0$ - - - \State $newkey \gets$ \Call{CreateNewKey}{$k_a, id_a$} - \State $newkeyinserted \gets false$ - \State $slotstoinsert \gets \emptyset$\\ - - \State $resize \gets $ \Call{ShouldResize}{ } \Comment{Check if we should resize} - \State $resize \gets resize \lor forceresize$ - \If{$resize$} - \State $newsize \gets$ \Call{CalcNewSize}{$max\_size$} - \State $DE \gets DE \cup \{$\Call{CreateQState}{$newsize$}$\}$ - \EndIf\\ - - \If{$RejectedSlotList \neq \emptyset$} - \State $DE \gets$ \Call{RejectedMessages}{$DE$} - \EndIf\\ - - \State $DE \gets$ \Call{MandatoryRescue}{$DE$} \Comment{Round 1 of rescue} - \If{$DE = NULL$} - \LeftComment{Data was going to fall off the end so try again with a forced resize} - \State \Return{\Call{TryInsertNewKey}{$k_a, id_a, true$}} - \EndIf\\ - - \State $DE \gets $\Call{Arbitrate}{$DE$}\\ - - \If{\Call{DEHasSpace}{$DE, newkey$}} \Comment{new key fits} - \State $DE \gets DE \cup newkey$ - \State $newkeyinserted \gets true$ - \EndIf\\ - - \LeftComment{Rescue data to fill slot data entry section} - \State $DE \gets$ \Call{OptionalRescue}{$DE$}\\ - - \LeftComment{Send to server.} - \State $\tuple{sendsuccess, newslots} \gets $ \Call{SendToServer}{$seq, DE, newsize$}\\ - - \LeftComment{Insert the slots into the local block chain} - \State \Call{DecryptValidateInsert}{$newslots, true$}\\ - - \State \Return{$newkeyinserted \land success$} \Comment{Return if succeeded or not} - -\EndFunction -\end{algorithmic} -\end{varwidth}% -} - - - -\subsection{Client Interfaces} - -% Put KV pair -\noindent\fbox{% -\begin{varwidth}{\dimexpr\linewidth-2\fboxsep-2\fboxrule\relax} -\textbf{Put Key Value Pair:}\\ -Puts a key value pair into the key value pair buffer\\ -\begin{algorithmic}[1] -\Function{PutKeyValue}{$k,v$} - \State $\tuple{seq, KV, Guard} \gets PendingTrans$\\ - - \LeftComment{Check if KV already has a key value pair for the specified key} - \State $DSet \gets \{\tuple{k_1,v_1} | \tuple{k_1,v_1} \in KV \land k_1 = k\}$\\ - - \If{$DSet \neq \emptyset$} - \State \Call{Error}{"Value for key already in most recent update"} - \EndIf\\ - - \State $KV \gets KV \cup \{\tuple{k,v}\}$ \Comment{Add key value pair} - \State $PendingTrans \gets \tuple{seq, KV, Guard}$ - \State \Call{CheckArbitrator}{$PendingTrans$} \Comment{Check that the transaction still valid} -\EndFunction -\end{algorithmic} -\end{varwidth}% -} - -% Get KV Pair Speculative -\noindent\fbox{% -\begin{varwidth}{\dimexpr\linewidth-2\fboxsep-2\fboxrule\relax} -\textbf{Get KV Pair Speculative:}\\ -Get the value for the key while speculating.\\ -\begin{algorithmic}[1] -\Function{GetValueSpeculate}{$k_a$} - %\State $\tuple{k,v} \gets \tuple{k,v}$ \textit{such that} $\tuple{k,v} \in SpeculatedKV \land k = k_a$ - - \State $\tuple{k,v} \gets \tuple{k,v}$ \textit{such that} $\tuple{k,v} \in SpeculatedKV \land k = k_a$ -\State \Return{$v$} -\EndFunction -\end{algorithmic} -\end{varwidth}% -} - -% Update -\noindent\fbox{% -\begin{varwidth}{\dimexpr\linewidth-2\fboxsep-2\fboxrule\relax} -\textbf{Update}\\ -Sync with the server and get all the latest slots.\\ -\begin{algorithmic}[1] -\Function{Update}{$ $} - \State $\tuple{seq, Dat} \gets $ \Call{MaxSlot}{$LocalSlots$} - \State $NewSlots \gets$ \Call{GetSlots}{$seq$} - \State \Call{DecryptValidateInsert}{$NewSlots, false$} -\EndFunction -\end{algorithmic} -\end{varwidth}% -} - -% Get KV Pair Committed -\noindent\fbox{% -\begin{varwidth}{\dimexpr\linewidth-2\fboxsep-2\fboxrule\relax} -\textbf{Get KV Pair Committed:}\\ -Get the value for the key which have been committed.\\ -\begin{algorithmic}[1] -\Function{GetValueCommit}{$k_a$} - \State $\tuple{k,v} \gets \tuple{k,v}$ \textit{such that} $\tuple{k,v} \in Committed \land k = k_a$ - \State \Return{$v$} -\EndFunction -\end{algorithmic} -\end{varwidth}% -} - -% Put guard condition -\noindent\fbox{% -\begin{varwidth}{\dimexpr\linewidth-2\fboxsep-2\fboxrule\relax} -\textbf{Put Guard:}\\ -Puts a guard transaction into the key value update. A guard is a key value with a logical operator ($lop$).\\ -\begin{algorithmic}[1] -\Function{PutGuard}{$k,v, lop$} - \State $\tuple{seq, KV, Guard} \gets PendingTrans$\\ - - \If{$\tuple{k,v, lop} \in Guard$} - \State \Return{} \Comment{Already have guard condition in update} - \EndIf\\ - - \State $Guard \gets Guard \cup \{\tuple{k,v,lop}\}$ - \State $PendingTrans \gets \tuple{seq, KV, Guard}$ - \State \Call{CheckArbitrator}{$PendingTrans$} \Comment{Check that the transaction still valid} -\EndFunction -\end{algorithmic} -\end{varwidth}% -} - -% Transaction Start -\noindent\fbox{% -\begin{varwidth}{\dimexpr\linewidth-2\fboxsep-2\fboxrule\relax} -\textbf{ Transaction Start:}\\ -Starts a transaction. Clears out the key value pair update buffer.\\ -\begin{algorithmic}[1] -\Function{TransactionStart}{$ $} - % \LeftComment{Reset the key value update buffer} - % \State $KVUpdate \gets \tuple{\emptyset, \emptyset}$ - \State $PendingTrans \gets NULL$ -\EndFunction -\end{algorithmic} -\end{varwidth}% -} - -% Transaction Commit -\noindent\fbox{% -\begin{varwidth}{\dimexpr\linewidth-2\fboxsep-2\fboxrule\relax} -\textbf{ Transaction Commit:}\\ -Commits the transaction into the block chain. Keeps attempting to insert the transaction into the block chain until it succeeds.\\ -\begin{algorithmic}[1] -\Function{Transaction Commit}{$ $} - \State $DKV \gets \emptyset$ - \State $pt \gets NULL$\\ - - \State $PendingTransQueue.$\Call{push}{$PendingTrans$}\\ - - \While{\Call{HasConnectionToServer}{ } $\land PendingTransQueue \neq \emptyset$} - \State $pt \gets PendingTransQueue.$\Call{peak}{ }\\ - - \If{\Call{TryInsertTransaction}{$pt, false$}} - \State $PendingTransQueue.$\Call{pop}{ } - \EndIf - \EndWhile\\ - - \LeftComment{Go Through local pending transactions and speculate} - \ForAll{$\tuple{KV, Guard} \in PendingTransQueue$} - \If{\Call{EvaluateGuard}{$Guard, SpeculatedKV$}} - \State $DKV \gets \{\tuple{k,v}| \tuple{k,v} \in SpeculatedKV \land \tuple{k',v'}\in KV \land k'=k\}$ - \State $SpeculatedKV \gets (SpeculatedKV \setminus DKV) \cup KV$ - \EndIf - \EndFor - -\EndFunction -\end{algorithmic} -\end{varwidth}% -} - - -%Create New Key -\noindent\fbox{% -\begin{varwidth}{\dimexpr\linewidth-2\fboxsep-2\fboxrule\relax} -\textbf{Create New Key:}\\ -Creates a new key and specifies which machine ID is the arbitrator. If there is already a new key entry in the block chain for this key name then do not insert into the chain, another client got there first. \\ -\begin{algorithmic}[1] -\Function{Transaction Commit}{$k_a, id_a$} - \State $success \gets false$\\ - \While{$\lnot success$} - \If{$\exists \tuple{k',id'} \in Arbitrator, k' = k_a$} - \State \Return{$false$} \Comment{Key already created} - \EndIf\\ - - \State $success \gets$ \Call{TryInsertNewKey}{$k_a, id_a, false$} - \EndWhile - - \State \Return{$true$} \Comment{If got here then insertion was correct} -\EndFunction -\end{algorithmic} -\end{varwidth}% -} - - -\end{document} diff --git a/doc2/makefile b/doc2/makefile deleted file mode 100644 index cff4a15..0000000 --- a/doc2/makefile +++ /dev/null @@ -1,8 +0,0 @@ -LATEX := pdflatex -halt-on-error - -default: - $(LATEX) iotcloud.tex - -clean: - rm -f *.dvi *.log *.aux *.blg *.bbl *~ - rm -f iotcloud.ps iotcloud.pdf diff --git a/src/java/.dir-locals.el b/src/java/.dir-locals.el deleted file mode 100644 index e166a2e..0000000 --- a/src/java/.dir-locals.el +++ /dev/null @@ -1,2 +0,0 @@ -((nil . ((indent-tabs-mode . t)))) - diff --git a/src/java/iotcloud/CloudComm.java b/src/java/iotcloud/CloudComm.java deleted file mode 100644 index ac906b1..0000000 --- a/src/java/iotcloud/CloudComm.java +++ /dev/null @@ -1,232 +0,0 @@ -package iotcloud; -import java.io.*; -import java.net.*; -import java.util.Arrays; -import javax.crypto.*; -import javax.crypto.spec.*; -import java.security.SecureRandom; - -/** - * This class provides a communication API to the webserver. It also - * validates the HMACs on the slots and handles encryption. - * @author Brian Demsky - * @version 1.0 - */ - - -class CloudComm { - String baseurl; - Cipher encryptCipher; - Cipher decryptCipher; - Mac mac; - String password; - SecureRandom random; - static final int SALT_SIZE = 8; - byte salt[]; - Table table; - - /** - * Empty Constructor needed for child class. - */ - - CloudComm() { - } - - /** - * Constructor for actual use. Takes in the url and password. - */ - - CloudComm(Table _table, String _baseurl, String _password) { - this.table=_table; - this.baseurl=_baseurl; - this.password = _password; - this.random = new SecureRandom(); - } - - /** - * Generates Key from password. - */ - - private SecretKeySpec initKey() { - try { - PBEKeySpec keyspec = new PBEKeySpec(password.toCharArray(), salt, 65536, 128); - SecretKey tmpkey = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256").generateSecret(keyspec); - return new SecretKeySpec(tmpkey.getEncoded(), "AES"); - } catch (Exception e) { - e.printStackTrace(); - throw new Error("Failed generating key."); - } - } - - /** - * Inits the HMAC generator. - */ - - private void initCrypt() { - try { - SecretKeySpec key=initKey(); - password = null; // drop password - mac = Mac.getInstance("HmacSHA256"); - mac.init(key); - encryptCipher =Cipher.getInstance("AES/ECB/PKCS5Padding"); - encryptCipher.init(Cipher.ENCRYPT_MODE, key); - decryptCipher =Cipher.getInstance("AES/ECB/PKCS5Padding"); - decryptCipher.init(Cipher.DECRYPT_MODE, key); - } catch (Exception e) { - e.printStackTrace(); - throw new Error("Failed To Initialize Ciphers"); - } - } - - /* - * Builds the URL for the given request. - */ - - private URL buildRequest(boolean isput, long sequencenumber, long maxentries) throws IOException { - String reqstring=isput?"req=putslot":"req=getslot"; - String urlstr=baseurl+"?"+reqstring+"&seq="+sequencenumber; - if (maxentries != 0) - urlstr += "&max="+maxentries; - return new URL(urlstr); - } - - public void setSalt() { - try { - salt = new byte[SALT_SIZE]; - random.nextBytes(salt); - URL url=new URL(baseurl+"?req=setsalt"); - URLConnection con=url.openConnection(); - HttpURLConnection http = (HttpURLConnection) con; - http.setRequestMethod("POST"); - http.setFixedLengthStreamingMode(salt.length); - http.setDoOutput(true); - http.connect(); - OutputStream os=http.getOutputStream(); - os.write(salt); - int responsecode=http.getResponseCode(); - if (responsecode != HttpURLConnection.HTTP_OK) - throw new Error("Invalid response"); - } catch (Exception e) { - e.printStackTrace(); - throw new Error("Failed setting salt"); - } - initCrypt(); - } - - private void getSalt() throws Exception { - URL url=new URL(baseurl+"?req=getsalt"); - URLConnection con=url.openConnection(); - HttpURLConnection http = (HttpURLConnection) con; - http.setRequestMethod("POST"); - http.connect(); - - InputStream is=http.getInputStream(); - DataInputStream dis=new DataInputStream(is); - int salt_length=dis.readInt(); - byte [] tmp=new byte[salt_length]; - dis.readFully(tmp); - salt=tmp; - } - - /* - * API for putting a slot into the queue. Returns null on success. - * On failure, the server will send slots with newer sequence - * numbers. - */ - - Slot[] putSlot(Slot slot, int max) { - try { - if (salt == null) { - getSalt(); - initCrypt(); - } - - long sequencenumber=slot.getSequenceNumber(); - byte[] bytes=slot.encode(mac); - bytes = encryptCipher.doFinal(bytes); - - URL url=buildRequest(true, sequencenumber, max); - URLConnection con=url.openConnection(); - HttpURLConnection http = (HttpURLConnection) con; - - http.setRequestMethod("POST"); - http.setFixedLengthStreamingMode(bytes.length); - http.setDoOutput(true); - http.connect(); - - OutputStream os=http.getOutputStream(); - os.write(bytes); - - InputStream is=http.getInputStream(); - DataInputStream dis=new DataInputStream(is); - byte[] resptype=new byte[7]; - dis.readFully(resptype); - if (Arrays.equals(resptype, "getslot".getBytes())) - return processSlots(dis); - else if (Arrays.equals(resptype, "putslot".getBytes())) - return null; - else - throw new Error("Bad response to putslot"); - } catch (Exception e) { - e.printStackTrace(); - throw new Error("putSlot failed"); - } - } - - /** - * Request the server to send all slots with the given - * sequencenumber or newer. - */ - - Slot[] getSlots(long sequencenumber) { - try { - if (salt == null) { - getSalt(); - initCrypt(); - } - - URL url=buildRequest(false, sequencenumber, 0); - URLConnection con=url.openConnection(); - HttpURLConnection http = (HttpURLConnection) con; - http.setRequestMethod("POST"); - http.connect(); - InputStream is=http.getInputStream(); - - DataInputStream dis=new DataInputStream(is); - - byte[] resptype=new byte[7]; - dis.readFully(resptype); - if (!Arrays.equals(resptype, "getslot".getBytes())) - throw new Error("Bad Response: "+new String(resptype)); - else - return processSlots(dis); - } catch (Exception e) { - e.printStackTrace(); - throw new Error("getSlots failed"); - } - } - - /** - * Method that actually handles building Slot objects from the - * server response. Shared by both putSlot and getSlots. - */ - - private Slot[] processSlots(DataInputStream dis) throws Exception { - int numberofslots=dis.readInt(); - int[] sizesofslots=new int[numberofslots]; - Slot[] slots=new Slot[numberofslots]; - for(int i=0; i - * @version 1.0 - */ - -abstract class Entry implements Liveness { - static final byte TypeKeyValue = 1; - static final byte TypeLastMessage = 2; - static final byte TypeRejectedMessage = 3; - static final byte TypeTableStatus = 4; - - /* Records whether the information is still live or has been - superceded by a newer update. */ - - private boolean islive = true; - private Slot parentslot; - - Entry(Slot _parentslot) { - parentslot = _parentslot; - } - - /** - * Static method for decoding byte array into Entry objects. First - * byte tells the type of entry. - */ - - static Entry decode(Slot slot, ByteBuffer bb) { - byte type=bb.get(); - switch(type) { - case TypeKeyValue: - return KeyValue.decode(slot, bb); - - case TypeLastMessage: - return LastMessage.decode(slot, bb); - - case TypeRejectedMessage: - return RejectedMessage.decode(slot, bb); - - case TypeTableStatus: - return TableStatus.decode(slot, bb); - - default: - throw new Error("Unrecognized Entry Type: "+type); - } - } - - /** - * Returns true if the Entry object is still live. - */ - - boolean isLive() { - return islive; - } - - /** - * Flags the entry object as dead. Also decrements the live count - * of the parent slot. - */ - - void setDead() { - islive = false; - parentslot.decrementLiveCount(); - } - - /** - * Serializes the Entry object into the byte buffer. - */ - - abstract void encode(ByteBuffer bb); - - /** - * Returns the size in bytes the entry object will take in the byte - * array. - */ - - abstract int getSize(); - - /** - * Returns a byte encoding the type of the entry object. - */ - - abstract byte getType(); - - /** - * Returns a copy of the Entry that can be added to a different slot. - */ - abstract Entry getCopy(Slot s); - -} diff --git a/src/java/iotcloud/IoTString.java b/src/java/iotcloud/IoTString.java deleted file mode 100644 index 19ebee3..0000000 --- a/src/java/iotcloud/IoTString.java +++ /dev/null @@ -1,105 +0,0 @@ -package iotcloud; - -import java.util.Arrays; - -/** - * IoTString is wraps the underlying byte string. We don't use the - * standard String class as we have bytes and not chars. - * @author Brian Demsky - * @version 1.0 - */ - - -final public class IoTString { - byte[] array; - int hashcode; - - private IoTString() { - } - - /** - * Builds an IoTString object around the byte array. This - * constructor makes a copy, so the caller is free to modify the byte array. - */ - - public IoTString(byte[] _array) { - array=(byte[]) _array.clone(); - hashcode=Arrays.hashCode(array); - } - - /** - * Converts the String object to a byte representation and stores it - * into the IoTString object. - */ - - public IoTString(String str) { - array=str.getBytes(); - hashcode=Arrays.hashCode(array); - } - - /** - * Internal methods to build an IoTString using the byte[] passed - * in. Caller is responsible for ensuring the byte[] is never - * modified. - */ - - static IoTString shallow(byte[] _array) { - IoTString i=new IoTString(); - i.array = _array; - i.hashcode = Arrays.hashCode(_array); - return i; - } - - /** - * Internal method to grab a reference to our byte array. Caller - * must not modify it. - */ - - byte[] internalBytes() { - return array; - } - - /** - * Returns the hashCode as computed by Arrays.hashcode(byte[]). - */ - - public int hashCode() { - return hashcode; - } - - /** - * Returns a String representation of the IoTString. - */ - - public String toString() { - return new String(array); - } - - /** - * Returns a copy of the underlying byte string. - */ - - public byte[] getBytes() { - return (byte[]) array.clone(); - } - - /** - * Returns true if two byte strings have the same content. - */ - - public boolean equals(Object o) { - if (o instanceof IoTString) { - IoTString i=(IoTString)o; - return Arrays.equals(array, i.array); - } - return false; - } - - /** - * Returns the length in bytes of the IoTString. - */ - - public int length() { - return array.length; - } -} diff --git a/src/java/iotcloud/KeyValue.java b/src/java/iotcloud/KeyValue.java deleted file mode 100644 index bed66a2..0000000 --- a/src/java/iotcloud/KeyValue.java +++ /dev/null @@ -1,61 +0,0 @@ -package iotcloud; -import java.nio.ByteBuffer; - -/** - * KeyValue entry for Slot. - * @author Brian Demsky - * @version 1.0 - */ - -class KeyValue extends Entry { - private IoTString key; - private IoTString value; - - KeyValue(Slot slot, IoTString _key, IoTString _value) { - super(slot); - key=_key; - value=_value; - } - - IoTString getKey() { - return key; - } - - IoTString getValue() { - return value; - } - - static Entry decode(Slot slot, ByteBuffer bb) { - int keylength=bb.getInt(); - int valuelength=bb.getInt(); - byte[] key=new byte[keylength]; - byte[] value=new byte[valuelength]; - bb.get(key); - bb.get(value); - return new KeyValue(slot, IoTString.shallow(key), IoTString.shallow(value)); - } - - void encode(ByteBuffer bb) { - bb.put(Entry.TypeKeyValue); - bb.putInt(key.length()); - bb.putInt(value.length()); - bb.put(key.internalBytes()); - bb.put(value.internalBytes()); - } - - int getSize() { - return 2*Integer.BYTES+key.length()+value.length()+Byte.BYTES; - } - - byte getType() { - return Entry.TypeKeyValue; - } - - public String toString() { - return value.toString(); - } - - Entry getCopy(Slot s) { - return new KeyValue(s, key, value); - } -} diff --git a/src/java/iotcloud/LastMessage.java b/src/java/iotcloud/LastMessage.java deleted file mode 100644 index c87c2e9..0000000 --- a/src/java/iotcloud/LastMessage.java +++ /dev/null @@ -1,55 +0,0 @@ -package iotcloud; - -import java.nio.ByteBuffer; - -/** - * This Entry records the last message sent by a given machine. - * @author Brian Demsky - * @version 1.0 - */ - - -class LastMessage extends Entry { - private long machineid; - private long seqnum; - - LastMessage(Slot slot, long _machineid, long _seqnum) { - super(slot); - machineid=_machineid; - seqnum=_seqnum; - } - - long getMachineID() { - return machineid; - } - - long getSequenceNumber() { - return seqnum; - } - - static Entry decode(Slot slot, ByteBuffer bb) { - long machineid=bb.getLong(); - long seqnum=bb.getLong(); - return new LastMessage(slot, machineid, seqnum); - } - - void encode(ByteBuffer bb) { - bb.put(Entry.TypeLastMessage); - bb.putLong(machineid); - bb.putLong(seqnum); - } - - int getSize() { - return 2*Long.BYTES+Byte.BYTES; - } - - byte getType() { - return Entry.TypeLastMessage; - } - - Entry getCopy(Slot s) { - return new LastMessage(s, machineid, seqnum); - } -} - - diff --git a/src/java/iotcloud/Liveness.java b/src/java/iotcloud/Liveness.java deleted file mode 100644 index 2c840e4..0000000 --- a/src/java/iotcloud/Liveness.java +++ /dev/null @@ -1,11 +0,0 @@ -package iotcloud; - -/** - * Interface common to both classes that record information about the - * last message sent by a machine. (Either a Slot or a LastMessage. - * @author Brian Demsky - * @version 1.0 - */ - -interface Liveness { -} diff --git a/src/java/iotcloud/Makefile b/src/java/iotcloud/Makefile deleted file mode 100644 index 2d45b63..0000000 --- a/src/java/iotcloud/Makefile +++ /dev/null @@ -1,17 +0,0 @@ -all: server - -JAVAC = javac -JAVADOC = javadoc -BIN_DIR = bin -DOCS_DIR = docs - -server: - $(JAVAC) -d $(BIN_DIR) *.java - -doc: server - $(JAVADOC) -private -d $(DOCS_DIR) *.java - -clean: - rm -r bin/* - rm -r docs/* - rm *~ diff --git a/src/java/iotcloud/Pair.java b/src/java/iotcloud/Pair.java deleted file mode 100644 index 73ed6bd..0000000 --- a/src/java/iotcloud/Pair.java +++ /dev/null @@ -1,23 +0,0 @@ -package iotcloud; - -class Pair { - private A a; - private B b; - - Pair(A a, B b) { - this.a=a; - this.b=b; - } - - A getFirst() { - return a; - } - - B getSecond() { - return b; - } - - public String toString() { - return "<"+a+","+b+">"; - } -} diff --git a/src/java/iotcloud/RejectedMessage.java b/src/java/iotcloud/RejectedMessage.java deleted file mode 100644 index 9c84f18..0000000 --- a/src/java/iotcloud/RejectedMessage.java +++ /dev/null @@ -1,88 +0,0 @@ -package iotcloud; -import java.nio.ByteBuffer; -import java.util.HashSet; - -/** - * Entry for tracking messages that the server rejected. We have to - * make sure that all clients know that this message was rejected to - * prevent the server from reusing these messages in an attack. - * @author Brian Demsky - * @version 1.0 - */ - - -class RejectedMessage extends Entry { - /* Machine identifier */ - private long machineid; - /* Oldest sequence number in range */ - private long oldseqnum; - /* Newest sequence number in range */ - private long newseqnum; - /* Is the machine identifier of the relevant slots equal to (or not - * equal to) the specified machine identifier. */ - private boolean equalto; - /* Set of machines that have not received notification. */ - private HashSet watchset; - - RejectedMessage(Slot slot, long _machineid, long _oldseqnum, long _newseqnum, boolean _equalto) { - super(slot); - machineid=_machineid; - oldseqnum=_oldseqnum; - newseqnum=_newseqnum; - equalto=_equalto; - } - - long getOldSeqNum() { - return oldseqnum; - } - - long getNewSeqNum() { - return newseqnum; - } - - boolean getEqual() { - return equalto; - } - - long getMachineID() { - return machineid; - } - - static Entry decode(Slot slot, ByteBuffer bb) { - long machineid=bb.getLong(); - long oldseqnum=bb.getLong(); - long newseqnum=bb.getLong(); - byte equalto=bb.get(); - return new RejectedMessage(slot, machineid, oldseqnum, newseqnum, equalto==1); - } - - void setWatchSet(HashSet _watchset) { - watchset=_watchset; - } - - void removeWatcher(long machineid) { - if (watchset.remove(machineid)) - if (watchset.isEmpty()) - setDead(); - } - - void encode(ByteBuffer bb) { - bb.put(Entry.TypeRejectedMessage); - bb.putLong(machineid); - bb.putLong(oldseqnum); - bb.putLong(newseqnum); - bb.put(equalto?(byte)1:(byte)0); - } - - int getSize() { - return 3*Long.BYTES + 2*Byte.BYTES; - } - - byte getType() { - return Entry.TypeRejectedMessage; - } - - Entry getCopy(Slot s) { - return new RejectedMessage(s, machineid, oldseqnum, newseqnum, equalto); - } -} diff --git a/src/java/iotcloud/Slot.java b/src/java/iotcloud/Slot.java deleted file mode 100644 index 5828fd3..0000000 --- a/src/java/iotcloud/Slot.java +++ /dev/null @@ -1,214 +0,0 @@ -package iotcloud; -import java.util.Vector; -import java.nio.ByteBuffer; -import javax.crypto.Mac; -import java.util.Arrays; - -/** - * Data structuring for holding Slot information. - * @author Brian Demsky - * @version 1.0 - */ - -class Slot implements Liveness { - /** Sets the slot size. */ - static final int SLOT_SIZE=2048; - /** Sets the size for the HMAC. */ - static final int HMAC_SIZE=32; - - /** Sequence number of the slot. */ - private long seqnum; - /** HMAC of previous slot. */ - private byte[] prevhmac; - /** HMAC of this slot. */ - private byte[] hmac; - /** Machine that sent this slot. */ - private long machineid; - /** Vector of entries in this slot. */ - private Vector entries; - /** Pieces of information that are live. */ - private int livecount; - /** Flag that indicates whether this slot is still live for - * recording the machine that sent it. */ - private boolean seqnumlive; - /** Number of bytes of free space. */ - private int freespace; - /** Reference to Table */ - private Table table; - - Slot(Table _table, long _seqnum, long _machineid, byte[] _prevhmac, byte[] _hmac) { - seqnum=_seqnum; - machineid=_machineid; - prevhmac=_prevhmac; - hmac=_hmac; - entries=new Vector(); - livecount=1; - seqnumlive=true; - freespace = SLOT_SIZE - getBaseSize(); - table=_table; - } - - Slot(Table _table, long _seqnum, long _machineid, byte[] _prevhmac) { - this(_table, _seqnum, _machineid, _prevhmac, null); - } - - Slot(Table _table, long _seqnum, long _machineid) { - this(_table, _seqnum, _machineid, new byte[HMAC_SIZE], null); - } - - byte[] getHMAC() { - return hmac; - } - - byte[] getPrevHMAC() { - return prevhmac; - } - - void addEntry(Entry e) { - e=e.getCopy(this); - entries.add(e); - livecount++; - freespace -= e.getSize(); - } - - private void 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. */ - - boolean hasSpace(Entry e) { - int newfreespace = freespace - e.getSize(); - return newfreespace >= 0; - } - - Vector getEntries() { - return entries; - } - - static Slot decode(Table table, byte[] array, Mac mac) { - mac.update(array, HMAC_SIZE, array.length-HMAC_SIZE); - byte[] realmac=mac.doFinal(); - - ByteBuffer bb=ByteBuffer.wrap(array); - byte[] hmac=new byte[HMAC_SIZE]; - byte[] prevhmac=new byte[HMAC_SIZE]; - bb.get(hmac); - bb.get(prevhmac); - if (!Arrays.equals(realmac, hmac)) - throw new Error("Server Error: Invalid HMAC! Potential Attack!"); - - long seqnum=bb.getLong(); - long machineid=bb.getLong(); - int numentries=bb.getInt(); - Slot slot=new Slot(table, seqnum, machineid, prevhmac, hmac); - - for(int i=0; i getLiveEntries(boolean resize) { - Vector liveEntries=new Vector(); - for(Entry entry: entries) { - if (entry.isLive()) { - if (!resize || entry.getType() != Entry.TypeTableStatus) - liveEntries.add(entry); - } - } - - if (seqnumlive && !resize) - liveEntries.add(new LastMessage(this, machineid, seqnum)); - - return liveEntries; - } - - /** - * Returns the sequence number of the slot. - */ - - long getSequenceNumber() { - return seqnum; - } - - /** - * Returns the machine that sent this slot. - */ - - long getMachineID() { - return machineid; - } - - /** - * Records that a newer slot records the fact that this slot was - * sent by the relevant machine. - */ - - void setDead() { - seqnumlive=false; - decrementLiveCount(); - } - - /** - * Update the count of live entries. - */ - - void decrementLiveCount() { - livecount--; - if (livecount==0) - table.decrementLiveCount(); - } - - /** - * Returns whether the slot stores any live information. - */ - - boolean isLive() { - return livecount > 0; - } - - public String toString() { - return "<"+getSequenceNumber()+">"; - } -} diff --git a/src/java/iotcloud/SlotBuffer.java b/src/java/iotcloud/SlotBuffer.java deleted file mode 100644 index 14bc926..0000000 --- a/src/java/iotcloud/SlotBuffer.java +++ /dev/null @@ -1,99 +0,0 @@ -package iotcloud; - -/** - * Circular buffer that holds the live set of slots. - * @author Brian Demsky - * @version 1.0 - */ - -class SlotBuffer { - static final int DEFAULT_SIZE = 128; - - private Slot[] array; - private int head; - private int tail; - private long oldestseqn; - - SlotBuffer() { - array=new Slot[DEFAULT_SIZE+1]; - head=tail=0; - oldestseqn=0; - } - - int size() { - if (head >= tail) - return head - tail; - return (array.length + head) - tail; - } - - int capacity() { - return array.length - 1; - } - - void resize(int newsize) { - if (newsize == (array.length-1)) - return; - Slot[] newarray = new Slot[newsize+1]; - int currsize = size(); - int index = tail; - for(int i=0; i < currsize; i++) { - newarray[i] = array[index]; - if ((++index) == array.length) - index = 0; - } - array = newarray; - tail = 0; - head = currsize; - } - - private void incrementHead() { - head++; - if (head >= array.length) - head=0; - } - - private void incrementTail() { - tail++; - if (tail >= array.length) - tail=0; - } - - void putSlot(Slot s) { - array[head]=s; - incrementHead(); - - if (oldestseqn==0) - oldestseqn = s.getSequenceNumber(); - - if (head==tail) { - incrementTail(); - oldestseqn++; - } - } - - Slot getSlot(long seqnum) { - int diff=(int) (seqnum-oldestseqn); - int index=diff + tail; - if (index >= array.length) { - if (head >= tail) - return null; - index-= array.length; - } - - if (index >= array.length) - return null; - - if (head >= tail && index >= head) - return null; - - return array[index]; - } - - long getOldestSeqNum() { - return oldestseqn; - } - - long getNewestSeqNum() { - return oldestseqn + size() - 1; - } -} diff --git a/src/java/iotcloud/SlotIndexer.java b/src/java/iotcloud/SlotIndexer.java deleted file mode 100644 index cecdf2d..0000000 --- a/src/java/iotcloud/SlotIndexer.java +++ /dev/null @@ -1,31 +0,0 @@ -package iotcloud; - -/** - * Slot indexer allows slots in both the slot buffer and the new - * server response to looked up in a consistent fashion. - * @author Brian Demsky - * @version 1.0 - */ - -class SlotIndexer { - private Slot[] updates; - private SlotBuffer buffer; - private long firstslotseqnum; - - SlotIndexer(Slot[] _updates, SlotBuffer _buffer) { - buffer = _buffer; - updates = _updates; - firstslotseqnum = updates[0].getSequenceNumber(); - } - - Slot getSlot(long seqnum) { - if (seqnum >= firstslotseqnum) { - int offset = (int) (seqnum - firstslotseqnum); - if (offset >= updates.length) - throw new Error("Invalid Slot Sequence Number Reference"); - else - return updates[offset]; - } else - return buffer.getSlot(seqnum); - } -} diff --git a/src/java/iotcloud/Table.java b/src/java/iotcloud/Table.java deleted file mode 100644 index 1d6259a..0000000 --- a/src/java/iotcloud/Table.java +++ /dev/null @@ -1,476 +0,0 @@ -package iotcloud; -import java.util.HashMap; -import java.util.Map; -import java.util.Iterator; -import java.util.HashSet; -import java.util.Arrays; -import java.util.Vector; -import java.util.Random; - -/** - * IoTTable data structure. Provides client inferface. - * @author Brian Demsky - * @version 1.0 - */ - -final public class Table { - private int numslots; //number of slots stored in buffer - - //table of key-value pairs - private HashMap table=new HashMap(); - - // machine id -> (sequence number, Slot or LastMessage); records last message by each client - private HashMap > lastmessagetable=new HashMap >(); - // machine id -> ... - private HashMap > watchlist = new HashMap >(); - private Vector rejectedmessagelist=new Vector(); - private SlotBuffer buffer; - private CloudComm cloud; - private long sequencenumber; //Largest sequence number a client has received - private long localmachineid; - private TableStatus lastTableStatus; - static final int FREE_SLOTS = 10; //number of slots that should be kept free - static final int SKIP_THRESHOLD = 10; - private long liveslotcount=0; - private int chance; - static final double RESIZE_MULTIPLE = 1.2; - static final double RESIZE_THRESHOLD = 0.75; - static final int REJECTED_THRESHOLD = 5; - private int resizethreshold; - private long lastliveslotseqn; //smallest sequence number with a live entry - private Random random=new Random(); - - public Table(String baseurl, String password, long _localmachineid) { - localmachineid=_localmachineid; - buffer = new SlotBuffer(); - numslots = buffer.capacity(); - setResizeThreshold(); - sequencenumber = 0; - cloud=new CloudComm(this, baseurl, password); - lastliveslotseqn = 1; - } - - public Table(CloudComm _cloud, long _localmachineid) { - localmachineid=_localmachineid; - buffer = new SlotBuffer(); - numslots = buffer.capacity(); - setResizeThreshold(); - sequencenumber = 0; - cloud=_cloud; - } - - public void rebuild() { - Slot[] newslots=cloud.getSlots(sequencenumber+1); - validateandupdate(newslots, true); - } - - public void update() { - Slot[] newslots=cloud.getSlots(sequencenumber+1); - - validateandupdate(newslots, false); - } - - public IoTString get(IoTString key) { - KeyValue kv=table.get(key); - if (kv != null) - return kv.getValue(); - else - return null; - } - - public void initTable() { - cloud.setSalt();//Set the salt - Slot s=new Slot(this, 1, localmachineid); - TableStatus status=new TableStatus(s, numslots); - s.addEntry(status); - Slot[] array=cloud.putSlot(s, numslots); - if (array == null) { - array = new Slot[] {s}; - /* update data structure */ - validateandupdate(array, true); - } else { - throw new Error("Error on initialization"); - } - } - - public String toString() { - return table.toString(); - } - - public IoTString put(IoTString key, IoTString value) { - while(true) { - KeyValue oldvalue=table.get(key); - if (tryput(key, value, false)) { - if (oldvalue==null) - return null; - else - return oldvalue.getValue(); - } - } - } - - void decrementLiveCount() { - liveslotcount--; - } - - - private void setResizeThreshold() { - int resize_lower=(int) (RESIZE_THRESHOLD * numslots); - resizethreshold=resize_lower-1+random.nextInt(numslots-resize_lower); - } - - private boolean tryput(IoTString key, IoTString value, boolean resize) { - Slot s=new Slot(this, sequencenumber+1, localmachineid, buffer.getSlot(sequencenumber).getHMAC()); - int newsize = 0; - if (liveslotcount > resizethreshold) { - resize=true; //Resize is forced - } - - if (resize) { - newsize = (int) (numslots * RESIZE_MULTIPLE); - TableStatus status=new TableStatus(s, newsize); - s.addEntry(status); - } - - if (! rejectedmessagelist.isEmpty()) { - /* TODO: We should avoid generating a rejected message entry if - * there is already a sufficient entry in the queue (e.g., - * equalsto value of true and same sequence number). */ - - long old_seqn=rejectedmessagelist.firstElement(); - if (rejectedmessagelist.size() > REJECTED_THRESHOLD) { - long new_seqn=rejectedmessagelist.lastElement(); - RejectedMessage rm=new RejectedMessage(s, localmachineid, old_seqn, new_seqn, false); - s.addEntry(rm); - } else { - long prev_seqn = -1; - int i=0; - /* Go through list of missing messages */ - for(; i liveentries = prevslot.getLiveEntries(resize); - for(Entry liveentry:liveentries) { - if (s.hasSpace(liveentry)) { - s.addEntry(liveentry); - } else if (seqn==firstiffull) { //if there's no space but the entry is about to fall off the queue - if (!resize) { - System.out.print("B"); //? - return tryput(key, value, true); - } - } - } - } - - KeyValue kv=new KeyValue(s, key, value); - boolean insertedkv=false; - if (s.hasSpace(kv)) { - s.addEntry(kv); - insertedkv=true; - } - - /* now go through live entries from least to greatest sequence number until - * either all live slots added, or the slot doesn't have enough room - * for SKIP_THRESHOLD consecutive entries*/ - int skipcount=0; - search: - for(; seqn <= newestseqnum; seqn++) { - Slot prevslot=buffer.getSlot(seqn); - //Push slot number forward - if (!seenliveslot) - lastliveslotseqn = seqn; - - if (!prevslot.isLive()) - continue; - seenliveslot = true; - Vector liveentries = prevslot.getLiveEntries(resize); - for(Entry liveentry:liveentries) { - if (s.hasSpace(liveentry)) - s.addEntry(liveentry); - else { - skipcount++; - if (skipcount > SKIP_THRESHOLD) - break search; - } - } - } - - int max=0; - if (resize) - max = newsize; - Slot[] array=cloud.putSlot(s, max); - if (array == null) { - array = new Slot[] {s}; - rejectedmessagelist.clear(); - } else { - if (array.length == 0) - throw new Error("Server Error: Did not send any slots"); - rejectedmessagelist.add(s.getSequenceNumber()); - insertedkv=false; - } - - /* update data structure */ - validateandupdate(array, true); - - return insertedkv; - } - - private void validateandupdate(Slot[] newslots, boolean acceptupdatestolocal) { - /* The cloud communication layer has checked slot HMACs already - before decoding */ - if (newslots.length==0) return; - - long firstseqnum=newslots[0].getSequenceNumber(); - if (firstseqnum <= sequencenumber) - throw new Error("Server Error: Sent older slots!"); - - SlotIndexer indexer = new SlotIndexer(newslots, buffer); - checkHMACChain(indexer, newslots); - - HashSet machineSet=new HashSet(lastmessagetable.keySet()); // - - initExpectedSize(firstseqnum); - for(Slot slot: newslots) { - processSlot(indexer, slot, acceptupdatestolocal, machineSet); - updateExpectedSize(); - } - - /* If there is a gap, check to see if the server sent us everything. */ - if (firstseqnum != (sequencenumber+1)) { - checkNumSlots(newslots.length); - if (!machineSet.isEmpty()) - throw new Error("Missing record for machines: "+machineSet); - } - - commitNewMaxSize(); - - /* Commit new to slots. */ - for(Slot slot:newslots) { - buffer.putSlot(slot); - liveslotcount++; - } - sequencenumber = newslots[newslots.length - 1].getSequenceNumber(); - } - - private int expectedsize, currmaxsize; - - private void checkNumSlots(int numslots) { - if (numslots != expectedsize) - throw new Error("Server Error: Server did not send all slots. Expected: "+expectedsize+" Received:"+numslots); - } - - private void initExpectedSize(long firstsequencenumber) { - long prevslots = firstsequencenumber; - expectedsize = (prevslots < ((long) numslots))? (int) prevslots : numslots; - currmaxsize = numslots; - } - - private void updateExpectedSize() { - expectedsize++; - if (expectedsize > currmaxsize) - expectedsize = currmaxsize; - } - - private void updateCurrMaxSize(int newmaxsize) { - currmaxsize=newmaxsize; - } - - private void commitNewMaxSize() { - if (numslots != currmaxsize) - buffer.resize(currmaxsize); - - numslots=currmaxsize; - setResizeThreshold(); - } - - private void processEntry(KeyValue entry, SlotIndexer indexer) { - IoTString key=entry.getKey(); - KeyValue oldvalue=table.get(key); - if (oldvalue != null) { - oldvalue.setDead(); - } - table.put(key, entry); - } - - private void processEntry(LastMessage entry, SlotIndexer indexer, HashSet machineSet) { - updateLastMessage(entry.getMachineID(), entry.getSequenceNumber(), entry, false, machineSet); - } - - private void processEntry(RejectedMessage entry, SlotIndexer indexer) { - long oldseqnum=entry.getOldSeqNum(); - long newseqnum=entry.getNewSeqNum(); - boolean isequal=entry.getEqual(); - long machineid=entry.getMachineID(); - for(long seqnum=oldseqnum; seqnum <= newseqnum; seqnum++) { - Slot slot=indexer.getSlot(seqnum); - if (slot != null) { - long slotmachineid=slot.getMachineID(); - if (isequal != (slotmachineid==machineid)) { - throw new Error("Server Error: Trying to insert rejected message for slot "+seqnum); - } - } - } - - HashSet watchset=new HashSet(); - for(Map.Entry > lastmsg_entry : lastmessagetable.entrySet()) { - long entry_mid=lastmsg_entry.getKey(); - /* We've seen it, don't need to continue to watch. Our next - * message will implicitly acknowledge it. */ - if (entry_mid == localmachineid) - continue; - Pair v=lastmsg_entry.getValue(); - long entry_seqn=v.getFirst(); - if (entry_seqn < newseqnum) { - addWatchList(entry_mid, entry); - watchset.add(entry_mid); - } - } - if (watchset.isEmpty()) - entry.setDead(); - else - entry.setWatchSet(watchset); - } - - private void addWatchList(long machineid, RejectedMessage entry) { - HashSet entries=watchlist.get(machineid); - if (entries == null) - watchlist.put(machineid, entries=new HashSet()); - entries.add(entry); - } - - private void processEntry(TableStatus entry, SlotIndexer indexer) { - int newnumslots=entry.getMaxSlots(); - updateCurrMaxSize(newnumslots); - if (lastTableStatus != null) - lastTableStatus.setDead(); - lastTableStatus = entry; - } - - private void updateLastMessage(long machineid, long seqnum, Liveness liveness, boolean acceptupdatestolocal, HashSet machineSet) { - machineSet.remove(machineid); - - HashSet watchset=watchlist.get(machineid); - if (watchset != null) { - for(Iterator rmit=watchset.iterator(); rmit.hasNext(); ) { - RejectedMessage rm=rmit.next(); - if (rm.getNewSeqNum() <= seqnum) { - /* Remove it from our watchlist */ - rmit.remove(); - /* Decrement machines that need to see this notification */ - rm.removeWatcher(machineid); - } - } - } - - if (machineid == localmachineid) { - /* Our own messages are immediately dead. */ - if (liveness instanceof LastMessage) { - ((LastMessage)liveness).setDead(); - } else if (liveness instanceof Slot) { - ((Slot)liveness).setDead(); - } else { - throw new Error("Unrecognized type"); - } - } - - - Pair lastmsgentry = lastmessagetable.put(machineid, new Pair(seqnum, liveness)); - if (lastmsgentry == null) - return; - - long lastmsgseqnum = lastmsgentry.getFirst(); - Liveness lastentry = lastmsgentry.getSecond(); - if (machineid != localmachineid) { - if (lastentry instanceof LastMessage) { - ((LastMessage)lastentry).setDead(); - } else if (lastentry instanceof Slot) { - ((Slot)lastentry).setDead(); - } else { - throw new Error("Unrecognized type"); - } - } - - if (machineid == localmachineid) { - if (lastmsgseqnum != seqnum && !acceptupdatestolocal) - throw new Error("Server Error: Mismatch on local machine sequence number"); - } else { - if (lastmsgseqnum > seqnum) - throw new Error("Server Error: Rollback on remote machine sequence number"); - } - } - - private void processSlot(SlotIndexer indexer, Slot slot, boolean acceptupdatestolocal, HashSet machineSet) { - updateLastMessage(slot.getMachineID(), slot.getSequenceNumber(), slot, acceptupdatestolocal, machineSet); - for(Entry entry : slot.getEntries()) { - switch(entry.getType()) { - case Entry.TypeKeyValue: - processEntry((KeyValue)entry, indexer); - break; - - case Entry.TypeLastMessage: - processEntry((LastMessage)entry, indexer, machineSet); - break; - - case Entry.TypeRejectedMessage: - processEntry((RejectedMessage)entry, indexer); - break; - - case Entry.TypeTableStatus: - processEntry((TableStatus)entry, indexer); - break; - - default: - throw new Error("Unrecognized type: "+entry.getType()); - } - } - } - - private void checkHMACChain(SlotIndexer indexer, Slot[] newslots) { - for(int i=0; i < newslots.length; i++) { - Slot currslot=newslots[i]; - Slot prevslot=indexer.getSlot(currslot.getSequenceNumber()-1); - if (prevslot != null && - !Arrays.equals(prevslot.getHMAC(), currslot.getPrevHMAC())) - throw new Error("Server Error: Invalid HMAC Chain"+currslot+" "+prevslot); - } - } -} diff --git a/src/java/iotcloud/TableStatus.java b/src/java/iotcloud/TableStatus.java deleted file mode 100644 index 62f3a6d..0000000 --- a/src/java/iotcloud/TableStatus.java +++ /dev/null @@ -1,45 +0,0 @@ -package iotcloud; -import java.nio.ByteBuffer; - -/** - * TableStatus entries record the current size of the data structure - * in slots. Used to remember the size and to perform resizes. - * @author Brian Demsky - * @version 1.0 - */ - - -class TableStatus extends Entry { - private int maxslots; - - TableStatus(Slot slot, int _maxslots) { - super(slot); - maxslots=_maxslots; - } - - int getMaxSlots() { - return maxslots; - } - - static Entry decode(Slot slot, ByteBuffer bb) { - int maxslots=bb.getInt(); - return new TableStatus(slot, maxslots); - } - - void encode(ByteBuffer bb) { - bb.put(Entry.TypeTableStatus); - bb.putInt(maxslots); - } - - int getSize() { - return Integer.BYTES+Byte.BYTES; - } - - byte getType() { - return Entry.TypeTableStatus; - } - - Entry getCopy(Slot s) { - return new TableStatus(s, maxslots); - } -} diff --git a/src/java/iotcloud/Test.java b/src/java/iotcloud/Test.java deleted file mode 100644 index ad976ac..0000000 --- a/src/java/iotcloud/Test.java +++ /dev/null @@ -1,95 +0,0 @@ -package iotcloud; - -/** - * Test cases. - * @author Brian Demsky - * @version 1.0 - */ - -public class Test { - public static void main(String[] args) { - if(args[0].equals("2")) - test2(); - else if(args[0].equals("3")) - test3(); - else if(args[0].equals("4")) - test4(); - else if(args[0].equals("5")) - test5(); - - } - - - - static Thread buildThread(String prefix, Table t) { - return new Thread() { - public void run() { - for(int i=0; i<10000; i++) { - String a=prefix+i; - IoTString ia=new IoTString(a); - t.put(ia, ia); - System.out.println(ia+"->"+t.get(ia)); - } - } - }; - } - - static void test5() { - Table t1=new Table("http://127.0.0.1/test.iotcloud/", "reallysecret", 321); - t1.rebuild(); - System.out.println(t1); - } - - static void test4() { - Table t1=new Table("http://127.0.0.1/test.iotcloud/", "reallysecret", 321); - Table t2=new Table("http://127.0.0.1/test.iotcloud/", "reallysecret", 351); - t1.rebuild(); - t2.rebuild(); - Thread thr1=buildThread("p1", t1); - Thread thr2=buildThread("p2", t2); - thr1.start(); - thr2.start(); - try { - thr1.join(); - thr2.join(); - } catch (Exception e) { - e.printStackTrace(); - } - } - - static void test3() { - Table t1=new Table("http://127.0.0.1/test.iotcloud/", "reallysecret", 321); - Table t2=new Table("http://127.0.0.1/test.iotcloud/", "reallysecret", 351); - t1.rebuild(); - t2.rebuild(); - for(int i=0; i<600; i++) { - String a="STR"+i; - String b="ABR"+i; - IoTString ia=new IoTString(a); - IoTString ib=new IoTString(b); - t1.put(ia, ia); - t2.put(ib, ib); - t1.update(); - System.out.println(ib+"->"+t1.get(ib)); - System.out.println(ia+"->"+t2.get(ia)); - } - } - - static void test2() { - Table t1=new Table("http://127.0.0.1/test.iotcloud/", "reallysecret", 321); - t1.initTable(); - Table t2=new Table("http://127.0.0.1/test.iotcloud/", "reallysecret", 351); - t2.update(); - for(int i=0; i<600; i++) { - String a="STR"+i; - String b="ABR"+i; - IoTString ia=new IoTString(a); - IoTString ib=new IoTString(b); - t1.put(ia, ia); - t2.put(ib, ib); - t1.update(); - System.out.println(ib+"->"+t1.get(ib)); - System.out.println(ia+"->"+t2.get(ia)); - } - } -} diff --git a/src/java/iotcloud/issues.txt b/src/java/iotcloud/issues.txt deleted file mode 100644 index 816b6b1..0000000 --- a/src/java/iotcloud/issues.txt +++ /dev/null @@ -1 +0,0 @@ -1) add better resizing support...gets stuck when it is full now... diff --git a/src/js/iotjs/.babelrc b/src/js/iotjs/.babelrc deleted file mode 100644 index 9d8d516..0000000 --- a/src/js/iotjs/.babelrc +++ /dev/null @@ -1 +0,0 @@ -{ "presets": ["es2015"] } diff --git a/src/js/iotjs/.bowerrc b/src/js/iotjs/.bowerrc deleted file mode 100644 index baa91a3..0000000 --- a/src/js/iotjs/.bowerrc +++ /dev/null @@ -1,3 +0,0 @@ -{ - "directory": "bower_components" -} \ No newline at end of file diff --git a/src/js/iotjs/.editorconfig b/src/js/iotjs/.editorconfig deleted file mode 100644 index e717f5e..0000000 --- a/src/js/iotjs/.editorconfig +++ /dev/null @@ -1,13 +0,0 @@ -# http://editorconfig.org -root = true - -[*] -indent_style = space -indent_size = 2 -end_of_line = lf -charset = utf-8 -trim_trailing_whitespace = true -insert_final_newline = true - -[*.md] -trim_trailing_whitespace = false diff --git a/src/js/iotjs/.jshintrc b/src/js/iotjs/.jshintrc deleted file mode 100644 index 63937d2..0000000 --- a/src/js/iotjs/.jshintrc +++ /dev/null @@ -1,18 +0,0 @@ -{ - "node": true, - "esnext": true, - "bitwise": true, - "curly": true, - "eqeqeq": true, - "immed": true, - "indent": 2, - "latedef": true, - "newcap": true, - "noarg": true, - "regexp": true, - "undef": true, - "unused": true, - "trailing": true, - "smarttabs": true, - "white": true -} diff --git a/src/js/iotjs/README.md b/src/js/iotjs/README.md deleted file mode 100644 index a384bd9..0000000 --- a/src/js/iotjs/README.md +++ /dev/null @@ -1,21 +0,0 @@ -iotjs -================================================== - -What does your library do? - -Getting Started --------------------------------------- - -- Install dependencies: `npm install` -- Run `npm test` to build your library -- Final src file in build directory. - -Usage --------------------------------------- - -How can I use it? - -Future Development --------------------------------------- - -What would you like to do but don't have the time for? diff --git a/src/js/iotjs/bower.json b/src/js/iotjs/bower.json deleted file mode 100644 index cb33217..0000000 --- a/src/js/iotjs/bower.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "name": "iotjs", - "version": "0.0.0", - "dependencies": {} -} - diff --git a/src/js/iotjs/examples/index.html b/src/js/iotjs/examples/index.html deleted file mode 100644 index 8613e8e..0000000 --- a/src/js/iotjs/examples/index.html +++ /dev/null @@ -1,11 +0,0 @@ - - - - - iotjs Example - - - - - - \ No newline at end of file diff --git a/src/js/iotjs/gulpfile.js b/src/js/iotjs/gulpfile.js deleted file mode 100644 index ed79d92..0000000 --- a/src/js/iotjs/gulpfile.js +++ /dev/null @@ -1,49 +0,0 @@ -var gulp = require('gulp'); -var gulpif = require('gulp-if'); -var clean = require('gulp-clean'); -var order = require('gulp-order'); -var rename = require('gulp-rename'); -var concat = require('gulp-concat'); -var jshint = require('gulp-jshint'); -var uglify = require('gulp-uglify'); -var stylish = require('jshint-stylish'); -var livereload = require('gulp-livereload'); -var sourcemaps = require('gulp-sourcemaps'); -var flags = require('minimist')(process.argv.slice(2)); - -// Gulp command line arguments -var production = flags.production || false; -var debug = flags.debug || !production; -var watch = flags.watch; - -gulp.task('build', ['clean'], function() { - // Single entry point to browserify - gulp.src(['src/*.js', 'vendor/*.js']) - .pipe(order([ // The order of concatenation - 'src/main.js' - ], {base: '.'})) - .pipe(gulpif(debug, sourcemaps.init())) - .pipe(gulpif(production, uglify())) - .pipe(concat('iotjs.js')) - .pipe(gulpif(debug, sourcemaps.write())) - .pipe(gulp.dest('./build/')) - .pipe(gulpif(watch, livereload())); -}); - -gulp.task('lint', function() { - return gulp.src('src/*.js') - .pipe(jshint()) - .pipe(jshint.reporter(stylish)) -}); - -gulp.task('clean', function() { - return gulp.src(['./build'], {read: false}) - .pipe(clean({force: true})); -}); - -gulp.task('watch', function() { - livereload.listen(); - gulp.watch('src/*', ['lint', 'build']); -}); - -gulp.task('default', ['clean', 'lint', 'build']); diff --git a/src/js/iotjs/orig/compat.txt b/src/js/iotjs/orig/compat.txt deleted file mode 100644 index 4006664..0000000 --- a/src/js/iotjs/orig/compat.txt +++ /dev/null @@ -1,4 +0,0 @@ -1.Byte[] -> Uint8Array -2.Static decode method in slot.js takes the table, uint8array and the secret key as the argument -3.Vector = array of entries [] -4.A Byte in a 'number' in javascript diff --git a/src/js/iotjs/orig/entry.js b/src/js/iotjs/orig/entry.js deleted file mode 100644 index 8421d5a..0000000 --- a/src/js/iotjs/orig/entry.js +++ /dev/null @@ -1,53 +0,0 @@ -class Entry{ - constructor(slot) { - if (slot && slot instanceof Slot) { - - this.TypeKeyValue = 1; - this.TypeLastmessage = 2; - this.TypeRejectedMessage = 3; - this.TypeTableStatus = 4; - this.liveStatus = true; - this.parentslot = slot; - - } - } - static decode(slot, bytebuffer) { - if (slot instanceof Slot && bytebuffer instanceof ByteBuffer) { - var type = bytebuffer.readByte(); - switch (type) { - case this.TypeKeyValue: - return KeyValue.decode(slot, bytebuffer); - case this.TypeLastmessage: - return LastMessage.decode(slot, bytebuffer); - case this.TypeRejectedMessage: - return RejectedMessage.decode(slot, bytebuffer); - case this.TypeTableStatus: - return TableStatus.decode(slot, bytebuffer); - default: - throw new Error("Unrecognized Entry Type: " + type); - } - } - } - isLive(){ - return this.liveStatus; - } - setDead() { - this.liveStatus = false; - parentslot.decrementLiveCount(); - } - - encode(bytebuffer){ - - } - getSize(){ - - } - getType(){ - - } - getCopy(slot){ - if(slot && slot instanceof Slot){ - - } - } -} \ No newline at end of file diff --git a/src/js/iotjs/orig/keyvalue.js b/src/js/iotjs/orig/keyvalue.js deleted file mode 100644 index 375b29d..0000000 --- a/src/js/iotjs/orig/keyvalue.js +++ /dev/null @@ -1,65 +0,0 @@ -class KeyValue extends Entry{ - constructor(slot,_key,_value){ - if(!(slot instanceof Slot && _key instanceof IoTString && _value instanceof IoTString)){ - throw new Error('Argument error '); - } - super(slot); - this.key = _key; - this.value = _value; - } - getKey(){ - return this.key; - } - getValue(){ - return this.value; - } - decode(slot,bb){ - if(!(slot instanceof Slot && bb instanceof ByteBuffer)){ - throw new Error('Argument error'); - } - var keylength = bb.getByte(); - var valuelength = bb.getByte(); - var key = new Uint8Array(keylength); - var value = new Uint8Array(valuelength); - var keystring = ''; - for(var i =0 ;i this.RESERVED_SPACE; - } - getEntries(){ - return this.entries; - } - static decode(table, array, key){ - var cond1 = (array && array instanceof Uint8Array); - if(cond1){ - var mac = crypto.HmacMD5(array.slice(this.HMAC_SIZE).join([separator='']),key); - - var realmac = new Uint8Array(mac.length); - for(var i=0; i< mac.length ; i++){ - realmac[i] = mac.charCodeAt(i); - } - - var bb = new ByteBuffer().wrap(array.join([separator=''])).flip(); - var hmac= new Uint8Array(this.HMAC_SIZE); - var prevhmac = new Uint8Array(this.HMAC_SIZE); - for(var i = 0; i entry.encode(bb)); - - var mac = crypto.HmacMD5(array.slice(this.HMAC_SIZE).join([separator='']),key); - var realmac = new Uint8Array(mac.length); - for(var i=0; i< mac.length ; i++){ - realmac[i] = mac.charCodeAt(i); - } - this.hmac = realmac; - bb.reset(); - bb.wrap(realmac.join([separator=''])); - return new Uint8Array(bb.toArrayBuffer()); - } - /** - * Returns the empty size of a Slot. Includes 2 HMACs, the machine - * identifier, the sequence number, and the number of entries. - */ - getBaseSize(){ - return 2*this.HMAC_SIZE+2*8+2*4; //Problematic area - } - - getLiveEntries(resize){ - var liveEntries = []; - this.entries.forEach(function(entry){ - if(entry.isLive === true){ - if(!resize || entry.getType() !== entry.TypeTableStatus){ - liveEntries.push(entry); - } - }; - }); - - if(this.seqnumlive && !resize){ - liveEntries.push(new LastMessage(this,this.machineid,this.seqnumlive)) - } - - return liveEntries; - } - - getSequenceNumber() { - return this.seqnum; - } - - getMachineID() { - return this.machineid; - } - - setDead() { - this.seqnumlive=false; - this.decrementLiveCount(); - } - - decrementLiveCount() { - this.livecount--; - if (this.livecount === 0) - this.table.decrementLiveCount(); - } - - isLive() { - return this.livecount > 0; - } - - toString() { - return '<'+this.getSequenceNumber()+'>'; - } - -} - \ No newline at end of file diff --git a/src/js/iotjs/orig/slotbuffer.js b/src/js/iotjs/orig/slotbuffer.js deleted file mode 100644 index 1e76971..0000000 --- a/src/js/iotjs/orig/slotbuffer.js +++ /dev/null @@ -1,89 +0,0 @@ -class SlotBuffer{ - constructor(){ - this.DEFAULT_SIZE = 128; - this.array = []; - this.head=0; - this.tail=0; - this.oldestseqn = 0; - } - size(){ - if(this.head>=this.tail){ - return this.head-this.tail; - } - return (this.array.length + this.head - this.tail); - } - capacity(){ - return this.array.length-1; - } - resize(newsize){ - if(newsize === (this.array.length-1)){ - return; - } - var newarray = []; - var currsize = this.size(); - var index = this.tail; - for(let i = 0 ; i= this.array.length){ - this.head=0; - } - } - incrementTail(){ - this.tail++; - if(this.tail >= this.array.length){ - this.tail=0; - } - } - putSlot(s){ - if(!(s instanceof Slot)){ - throw new Error("Error with arguments. Argument should be a slot object"); - } - this.array[this.head]=s; - this.incrementHead(); - - if(this.oldestseqn ===0){ - this.oldestseqn = s.getSequenceNumber(); - } - - if(this.head === this.tail){ - this.incrementTail(); - this.oldestseqn++; - } - } - getSlot(seqnum){ - var diff = (seqnum - this.oldestseqn); - var index = diff + this.tail; - if(index >= this.array.length){ - if(this.head >= this.tail){ - return null; - } - index = index - this.array.length; - } - if(index >= this.array.length){ - return null; - } - - if(this.head >= this.tail && index >= this.head){ - return null; - } - - return this.array[index]; - } - - getOldestSeqNum(){ - return this.oldestseqn; - } - getNewestSeqNum(){ - return this.oldestseqn + this.size() -1 - } -} \ No newline at end of file diff --git a/src/js/iotjs/orig/slotindexer.js b/src/js/iotjs/orig/slotindexer.js deleted file mode 100644 index da738ff..0000000 --- a/src/js/iotjs/orig/slotindexer.js +++ /dev/null @@ -1,27 +0,0 @@ -class SlotIndexer{ - constructor(_updates,_buffer){ - // updates is an array of slot objects - // buffer is an instanceof slotbuffer constructor object in slotbuffer.js - this.updates = _updates; - if(_buffer && _buffer instanceof SlotBuffer){ - this.buffer = _buffer; - }else{ - throw new Error("Argument error Buffer should be an instance of SlotBuffer"); - } - this.firstslotseqnum = this.updates[0].getSequenceNumber(); - } - - getSlot(seqnum){ - if(seqnum >= this.firstslotseqnum){ - var offset = seqnum - this.firstslotseqnum; - if(offset >= this.updates.length){ - throw new Error('Invalid Slot Sequence Number Reference'); - }else{ - return this.updates[offset]; - } - }else{ - return this.buffer.getSlot(seqnum); - } - } - -} \ No newline at end of file diff --git a/src/js/iotjs/orig/tablestatus.js b/src/js/iotjs/orig/tablestatus.js deleted file mode 100644 index 06f8f25..0000000 --- a/src/js/iotjs/orig/tablestatus.js +++ /dev/null @@ -1,34 +0,0 @@ -class TableStatus extends Entry{ - constructor(slot,_maxslots){ - super(slot); - this.maxslots = _maxslots; - } - getMaxSlots(){ - return this.maxslots; - } - static decode(slot,bb){ - //bb is an object of the type bytebuffer See main.js file and its require section - //for more details - if(!(bb instanceof ByteBuffer && slot instanceof Slot)){ - throw new Error('Argument Error: bb is not an instanceof Bytebuffer'); - } - this.maxslots = bb.readByte(); - return new TableStatus(slot,this.maxslots); - } - encode(bb){ - bb.writeByte(Entry.TypeTableStatus); - bb.writeInt8(this.maxslots); - } - getSize(){ - return 4+1; - } - getType(){ - return Entry.TypeTableStatus; - } - getcopy(s){ - if(!(s instanceof Slot)){ - throw new Error('Argument Error: s is not an instanceof Slot'); - } - return new TableStatus(s,this.maxslots); - } -} \ No newline at end of file diff --git a/src/js/iotjs/package.json b/src/js/iotjs/package.json deleted file mode 100644 index 277b0ba..0000000 --- a/src/js/iotjs/package.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "name": "iotjs", - "version": "0.0.0", - "scripts": { - "test": "gulp && node ./test/test.js" - }, - "dependencies": { - "bytebuffer": "^5.0.1", - "crypto-js": "^3.1.6", - "gulp": "3.8.11", - "gulp-clean": "0.3.1", - "gulp-concat": "2.5.2", - "gulp-if": "1.2.5", - "gulp-jshint": "1.9.4", - "gulp-livereload": "3.8.0", - "gulp-load-plugins": "0.8.1", - "gulp-order": "1.1.1", - "gulp-rename": "1.2.0", - "gulp-sourcemaps": "1.5.1", - "gulp-uglify": "1.1.0", - "jshint-stylish": "1.0.1", - "minimist": "1.1.1", - "node-forge": "^0.6.41", - "object-hash": "^1.1.3", - "request": "^2.74.0", - "underscore": "^1.8.3" - }, - "devDependencies": { - "babel-cli": "^6.11.4", - "babel-preset-es2015": "^6.9.0", - "browserify": "^13.1.0" - } -} diff --git a/src/js/iotjs/src/entry.js b/src/js/iotjs/src/entry.js deleted file mode 100644 index e4a47a3..0000000 --- a/src/js/iotjs/src/entry.js +++ /dev/null @@ -1,72 +0,0 @@ -"use strict"; - -var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); - -function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } - -var Entry = function () { - function Entry(slot) { - _classCallCheck(this, Entry); - - if (slot && slot instanceof Slot) { - - this.TypeKeyValue = 1; - this.TypeLastmessage = 2; - this.TypeRejectedMessage = 3; - this.TypeTableStatus = 4; - this.liveStatus = true; - this.parentslot = slot; - } - } - - _createClass(Entry, [{ - key: "isLive", - value: function isLive() { - return this.liveStatus; - } - }, { - key: "setDead", - value: function setDead() { - this.liveStatus = false; - parentslot.decrementLiveCount(); - } - - //must be overriden. - - }, { - key: "encode", - value: function encode(bytebuffer) {} - }, { - key: "getSize", - value: function getSize() {} - }, { - key: "getType", - value: function getType() {} - }, { - key: "getCopy", - value: function getCopy(slot) { - if (slot && slot instanceof Slot) {} - } - }], [{ - key: "decode", - value: function decode(slot, bytebuffer) { - if (slot instanceof Slot && bytebuffer instanceof ByteBuffer) { - var type = bytebuffer.readByte(); - switch (type) { - case this.TypeKeyValue: - return KeyValue.decode(slot, bytebuffer); - case this.TypeLastmessage: - return LastMessage.decode(slot, bytebuffer); - case this.TypeRejectedMessage: - return RejectedMessage.decode(slot, bytebuffer); - case this.TypeTableStatus: - return TableStatus.decode(slot, bytebuffer); - default: - throw new Error("Unrecognized Entry Type: " + type); - } - } - } - }]); - - return Entry; -}(); \ No newline at end of file diff --git a/src/js/iotjs/src/iotstring.js b/src/js/iotjs/src/iotstring.js deleted file mode 100644 index 5a350e8..0000000 --- a/src/js/iotjs/src/iotstring.js +++ /dev/null @@ -1,81 +0,0 @@ -var _createClass = function() { - function defineProperties(target, props) { - for (var i = 0; i < props.length; i++) { - var descriptor = props[i]; - descriptor.enumerable = descriptor.enumerable || false; - descriptor.configurable = true; - if ("value" in descriptor) descriptor.writable = true; - Object.defineProperty(target, descriptor.key, descriptor); - } - } - return function(Constructor, protoProps, staticProps) { - if (protoProps) defineProperties(Constructor.prototype, protoProps); - if (staticProps) defineProperties(Constructor, staticProps); - return Constructor; - }; -}(); - -function _classCallCheck(instance, Constructor) { - if (!(instance instanceof Constructor)) { - throw new TypeError("Cannot call a class as a function"); - } -} -var IoTString = function() { - function IoTString(arg) { - _classCallCheck(this, IoTString); - if (arg === undefined) { - this.array = new Uint8Array(); - this.hashcode = ''; - } else if (arg && typeof arg === "string") { - this.array = new Uint8Array(arg.length); - for (var i = 0; i < arg.length; ++i) { - this.array[i] = arg.charCodeAt(i); - } - this.hashcode = hash(this.array); - } else if (arg && arg instanceof Uint8Array) { - this.array = arg; - this.hashcode = hashcode(arg); - } - } - _createClass(IoTString, [{ - key: "shallow", - value: function shallow(arg) { - if (arg && arg instanceof Uint8Array) { - var i = new IotString(arg); - return i; - } - } - }, { - key: "internalBytes", - value: function internalBytes() { - return this.array; - } - }, { - key: "hashCode", - value: function hashCode() { - return this.hashcode; - } - }, { - key: "toString", - value: function toString() { - return this.array.toString(); - } - }, { - key: "getBytes", - value: function getBytes() { - var obj; - return _.extend(obj, this.array); - } - }, { - key: "equals", - value: function equals(arr) { - return _.isEqual(arr, this.array); - } - }, { - key: "length", - value: function length() { - return this.array.length; - } - }]); - return IoTString; -}(); \ No newline at end of file diff --git a/src/js/iotjs/src/keyvalue.js b/src/js/iotjs/src/keyvalue.js deleted file mode 100644 index a2c02d0..0000000 --- a/src/js/iotjs/src/keyvalue.js +++ /dev/null @@ -1,99 +0,0 @@ -'use strict'; - -var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); - -function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } - -function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } - -function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } - -var KeyValue = function (_Entry) { - _inherits(KeyValue, _Entry); - - function KeyValue(slot, _key, _value) { - _classCallCheck(this, KeyValue); - - if (!(slot instanceof Slot && _key instanceof IoTString && _value instanceof IoTString)) { - throw new Error('Argument error '); - } - - var _this = _possibleConstructorReturn(this, Object.getPrototypeOf(KeyValue).call(this, slot)); - - _this.key = _key; - _this.value = _value; - return _this; - } - - _createClass(KeyValue, [{ - key: 'getKey', - value: function getKey() { - return this.key; - } - }, { - key: 'getValue', - value: function getValue() { - return this.value; - } - }, { - key: 'decode', - value: function decode(slot, bb) { - if (!(slot instanceof Slot && bb instanceof ByteBuffer)) { - throw new Error('Argument error'); - } - var keylength = bb.getByte(); - var valuelength = bb.getByte(); - var key = new Uint8Array(keylength); - var value = new Uint8Array(valuelength); - var keystring = ''; - for (var i = 0; i < keylength; i++) { - keystring += bb.readByte(); - } - var valuestring = ''; - for (var j = 0; j < keylength; j++) { - valuestring += bb.readByte(); - } - for (var k = 0; k < keystring.length; k++) { - key[k] = keystring.charCodeAt(k); - } - for (var l = 0; l < valuestring.length; l++) { - value[l] = valuestring.charCodeAt(l); - } - return new KeyValue(slot, IoTString.shallow(key), IoTString.shallow(value)); - } - }, { - key: 'encode', - value: function encode(bb) { - if (!(bb instanceof ByteBuffer)) { - throw new Error('argument error'); - } - bb.writeByte(Entry.TypeKeyValue); - bb.writeByte(this.key.length()); - bb.writeByte(this.value.length()); - bb.concat(this.key.internalBytes()); - bb.concat(this.value.internalBytes()); - } - }, { - key: 'getSize', - value: function getSize() { - return 2 * 4 + this.jey.length() + this.value.length() + 1; - } - }, { - key: 'getType', - value: function getType() { - return Entry.TypeKeyValue; - } - }, { - key: 'toString', - value: function toString() { - return this.value.toString(); - } - }, { - key: 'getCopy', - value: function getCopy(s) { - return new KeyValue(s, this.key, this.value); - } - }]); - - return KeyValue; -}(Entry); \ No newline at end of file diff --git a/src/js/iotjs/src/lastmessage.js b/src/js/iotjs/src/lastmessage.js deleted file mode 100644 index 8ccb06b..0000000 --- a/src/js/iotjs/src/lastmessage.js +++ /dev/null @@ -1,73 +0,0 @@ -'use strict'; - -var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); - -function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } - -function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } - -function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } - -var LastMessage = function (_Entry) { - _inherits(LastMessage, _Entry); - - function LastMessage(slot, _machineid, _seqnum) { - _classCallCheck(this, LastMessage); - - var _this = _possibleConstructorReturn(this, Object.getPrototypeOf(LastMessage).call(this, slot)); - - _this.machineid = _machineid; - _this.seqnum = _seqnum; - return _this; - } - - _createClass(LastMessage, [{ - key: 'getMachineID', - value: function getMachineID() { - return this.machineid; - } - }, { - key: 'getSequenceNumber', - value: function getSequenceNumber() { - return this.seqnum; - } - }, { - key: 'decode', - value: function decode(slot, bb) { - //slot and bb are instancesof Slot and ByteBuffer - if (!(slot instanceof Slot && bb instanceof ByteBuffer)) { - throw new Error('Problem with the Arguments'); - } - var machineid = bb.readByte(); - var seqnum = bb.readByte(); - return new LastMessage(slot, machineid, seqnum); - } - }, { - key: 'encode', - value: function encode(bb) { - bb.writeByte(Entry.TypeLastMessage); - bb.writeByte(this.machineid); - bb.writeByte(this.seqnum); - } - }, { - key: 'getSize', - value: function getSize() { - return 2 * (1 + 1); - } - }, { - key: 'getType', - value: function getType() { - return Entry.TypeLastMessage; - } - }, { - key: 'getCopy', - value: function getCopy(s) { - if (!(s instanceof Slot)) { - throw new Error('Argument must be a slot object'); - } - return new LastMessage(s, this.machineid, this.seqnum); - } - }]); - - return LastMessage; -}(Entry); \ No newline at end of file diff --git a/src/js/iotjs/src/liveness.js b/src/js/iotjs/src/liveness.js deleted file mode 100644 index 22cbd3f..0000000 --- a/src/js/iotjs/src/liveness.js +++ /dev/null @@ -1,5 +0,0 @@ -function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } - -var Liveness = function Liveness() { - _classCallCheck(this, Liveness); -}; \ No newline at end of file diff --git a/src/js/iotjs/src/main.js b/src/js/iotjs/src/main.js deleted file mode 100644 index f8f03e7..0000000 --- a/src/js/iotjs/src/main.js +++ /dev/null @@ -1,66 +0,0 @@ -/* jshint devel:true */ -"use strict"; -console.log('Welcome to iotjs-www', '\n\n'); -// set up the base line.. -// Using browserify to set up browser exports -var crypto = require('crypto-js'); -var _ = require('underscore'); -var ByteBuffer = require('bytebuffer'); -var hash = require('object-hash'); -var forge = require('node-forge'); -(function() { - var root = this; - // iot namespace main constructor - var iot = function(obj) { - if (obj instanceof iot) return obj; - if (!(this instanceof iot)) return new iot(obj); - this.iot = obj; - }; - // export iot to the global exports - if (typeof exports !== 'undefined') { - if (typeof module !== 'undefined' && module.exports) { - exports = module.exports = iot; - } - exports.iot = iot; - } else { - root.iot = iot; - } - - - iot.baselinetest = function() { - // baseline test - console.log('its alive!!!'); - console.log(); - - - //local hash test - console.log(hash('hello man')); - console.log(typeof hash('hello man')); - console.log(); - - - //Pair test - var p = new Pair(1, 2); - console.log(p.toString()); - console.log(); - - - //iotstring test - var i = new IoTString('hello'); - console.log(i.length()); - console.log(); - - - //local crypto test - var data = [{id: 1}, {id: 2}]; - // Encrypt - var ciphertext = crypto.AES.encrypt(JSON.stringify(data), 'secret key 123'); - // Decrypt - var bytes = crypto.AES.decrypt(ciphertext.toString(), 'secret key 123'); - var decryptedData = JSON.parse(bytes.toString(crypto.enc.Utf8)); - // console.log(decryptedData); - - var e = crypto.HmacMD5("Message", "Secret Passphrase"); - console.log(typeof e.toString()); - } -}()) \ No newline at end of file diff --git a/src/js/iotjs/src/pair.js b/src/js/iotjs/src/pair.js deleted file mode 100644 index e2467e3..0000000 --- a/src/js/iotjs/src/pair.js +++ /dev/null @@ -1,32 +0,0 @@ -var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); - -function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } - -var Pair = function () { - function Pair(a, b) { - _classCallCheck(this, Pair); - - this.a = a; - this.b = b; - } - - _createClass(Pair, [{ - key: 'getFirst', - value: function getFirst() { - return this.a; - } - }, { - key: 'getSecond', - value: function getSecond() { - return this.b; - } - }, { - key: 'toString', - value: function toString() { - var str = '<' + this.a + ',' + this.b + '>'; - return str; - } - }]); - - return Pair; -}(); \ No newline at end of file diff --git a/src/js/iotjs/src/rejectedmessage.js b/src/js/iotjs/src/rejectedmessage.js deleted file mode 100644 index 7c825c8..0000000 --- a/src/js/iotjs/src/rejectedmessage.js +++ /dev/null @@ -1,101 +0,0 @@ -"use strict"; - -var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); - -function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } - -function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } - -function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } - -var RejectedMessage = function (_Entry) { - _inherits(RejectedMessage, _Entry); - - function RejectedMessage(slot, _machineid, _oldseqnum, _newseqnum, _equalto) { - _classCallCheck(this, RejectedMessage); - - var _this = _possibleConstructorReturn(this, Object.getPrototypeOf(RejectedMessage).call(this, slot)); - - _this.machineid = _machineid; - _this.oldseqnum = _oldseqnum; - _this.newseqnum = _newseqnum; - _this.equalto = _equalto; - _this.watchset = new Set(); - return _this; - } - - _createClass(RejectedMessage, [{ - key: "getOldSeqNum", - value: function getOldSeqNum() { - return this.oldseqnum; - } - }, { - key: "getNewSeqNum", - value: function getNewSeqNum() { - return this.newseqnum; - } - }, { - key: "getEqual", - value: function getEqual() { - return this.equalto; - } - }, { - key: "getMachineID", - value: function getMachineID() { - return this.machineid; - } - }, { - key: "setWatchSet", - value: function setWatchSet(_watchset) { - this.watchset = _watchset; - } - }, { - key: "removeWatcher", - value: function removeWatcher(_machineid) { - if (this.watchset.remove(_machineid)) { - if (this.watchset.isEmpty()) { - this.setDead(); - } - } - } - }, { - key: "encode", - value: function encode(bb) { - bb.writeByte(Entry.TypeRejectedMessage); - bb.writeInt64(this.machineid); - bb.writeInt64(this.oldseqnum); - bb.writeInt64(this.newseqnum); - if (this.equalto === true) { - bb.writebyte(1); - } else { - bb.writebyte(0); - } - } - }, { - key: "getSize", - value: function getSize() { - return 3 * 8 + 2 * 1; - } - }, { - key: "getType", - value: function getType() { - return Entry.TypeRejectedMessage; - } - }, { - key: "getCopy", - value: function getCopy(s) { - return new RejectedMessage(s, this.machineid, this.oldseqnum, this.newseqnum, this.equalto); - } - }], [{ - key: "decode", - value: function decode(slot, bb) { - this.machineid = bb.readByte(); - this.oldseqnum = bb.readInt64(); - this.newseqnum = bb.readInt64(); - this.equalto = bb.readbyte(); - return new RejectedMessage(this.slot, this.machineid, this.oldseqnum, this.newseqnum, this.equalto === 1); - } - }]); - - return RejectedMessage; -}(Entry); \ No newline at end of file diff --git a/src/js/iotjs/src/slot.js b/src/js/iotjs/src/slot.js deleted file mode 100644 index c283546..0000000 --- a/src/js/iotjs/src/slot.js +++ /dev/null @@ -1,208 +0,0 @@ -"use strict"; - -var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); - -function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } - -var Slot = function () { - function Slot(table, seqnum, machineid, prevhmac, hmac) { - _classCallCheck(this, Slot); - - this.SLOT_SIZE = 2048; - this.RESERVED_SPACE = 64; - this.HMAC_SIZE = 32; - if (typeof seqnum === "number") { - this.seqnum = seqnum; - } else { - throw new Error("seqnum should be a number"); - } - if (typeof machineid === "number") { - this.machineid = machineid; - } else { - throw new Error("machine should be a number"); - } - this.livecount = 1; - this.seqnumlive = true; - if (prevhmac && prevhmac instanceof Uint8Array) { - this.prevhmac = prevhmac; - } else { - this.prevhmac = new Uint8Array(this.HMAC_SIZE); - } - if (hmac && hmac instanceof Uint8Array) { - this.hmac = hmac; - } else { - this.hmac = null; - } - this.entries = []; - this.freespace = this.SLOT_SIZE - getBaseSize(); //??????? - this.table = table; - } - - _createClass(Slot, [{ - key: "getHMAC", - value: function getHMAC() { - return this.hmac; - } - }, { - key: "getPrevHmac", - value: function getPrevHmac() { - return this.prevhmac; - } - }, { - key: "addEntry", - value: function addEntry(entry) { - if (entry && entry instanceof Entry) { - var obj; - this.entries.push(_.extend(obj, entry)); - this.livecount++; - this.freespace -= entry.getSize(); - } - } - }, { - key: "addShallowEntry", - value: function addShallowEntry(entry) { - if (entry && entry instanceof Entry) { - this.entries.push(entry); - this.livecount++; - this.freespace -= entry.getSize(); - } - } - }, { - key: "hasSpace", - value: function hasSpace(entry) { - var newfreespace = this.freespace - entry.getSize(); - return newfreespace > this.RESERVED_SPACE; - } - }, { - key: "getEntries", - value: function getEntries() { - return this.entries; - } - }, { - key: "encode", - value: function encode(key) { - var array = new Uint8Array(this.SLOT_SIZE); - var bb = new ByteBuffer().wrap(array.join([separator = ''])); - //leave space for slot HMAC - bb.skip(this.HMAC_SIZE); - bb.writeIString(this.prevhmac.join([separator = ''])); - bb.writeInt64(this.seqnum); - bb.writeInt64(this.machineid); - bb.writeByte(this.entries.length); - this.entries.forEach(function (entry) { - return entry.encode(bb); - }); - - var mac = crypto.HmacMD5(array.slice(this.HMAC_SIZE).join([separator = '']), key); - var realmac = new Uint8Array(mac.length); - for (var i = 0; i < mac.length; i++) { - realmac[i] = mac.charCodeAt(i); - } - this.hmac = realmac; - bb.reset(); - bb.wrap(realmac.join([separator = ''])); - return new Uint8Array(bb.toArrayBuffer()); - } - /** - * Returns the empty size of a Slot. Includes 2 HMACs, the machine - * identifier, the sequence number, and the number of entries. - */ - - }, { - key: "getBaseSize", - value: function getBaseSize() { - return 2 * this.HMAC_SIZE + 2 * 8 + 2 * 4; //Problematic area - } - }, { - key: "getLiveEntries", - value: function getLiveEntries(resize) { - var liveEntries = []; - this.entries.forEach(function (entry) { - if (entry.isLive === true) { - if (!resize || entry.getType() !== entry.TypeTableStatus) { - liveEntries.push(entry); - } - } - }); - - if (this.seqnumlive && !resize) { - liveEntries.push(new LastMessage(this, this.machineid, this.seqnumlive)); - } - - return liveEntries; - } - }, { - key: "getSequenceNumber", - value: function getSequenceNumber() { - return this.seqnum; - } - }, { - key: "getMachineID", - value: function getMachineID() { - return this.machineid; - } - }, { - key: "setDead", - value: function setDead() { - this.seqnumlive = false; - this.decrementLiveCount(); - } - }, { - key: "decrementLiveCount", - value: function decrementLiveCount() { - this.livecount--; - if (this.livecount === 0) this.table.decrementLiveCount(); - } - }, { - key: "isLive", - value: function isLive() { - return this.livecount > 0; - } - }, { - key: "toString", - value: function toString() { - return '<' + this.getSequenceNumber() + '>'; - } - }], [{ - key: "decode", - value: function decode(table, array, key) { - var cond1 = array && array instanceof Uint8Array; - if (cond1) { - var mac = crypto.HmacMD5(array.slice(this.HMAC_SIZE).join([separator = '']), key); - - var realmac = new Uint8Array(mac.length); - for (var i = 0; i < mac.length; i++) { - realmac[i] = mac.charCodeAt(i); - } - - var bb = new ByteBuffer().wrap(array.join([separator = ''])).flip(); - var hmac = new Uint8Array(this.HMAC_SIZE); - var prevhmac = new Uint8Array(this.HMAC_SIZE); - for (var i = 0; i < this.HMAC_SIZE; i++) { - hmac[i] = bb.readByte(); - } - for (var j = 0; j < this.HMAC_SIZE; j++) { - prevhmac[j] = bb.readByte(); - } - //shallow compare - for (var k = 0; k < this.HMAC_SIZE; k++) { - if ((hmac[k] !== realmac[k])) { - throw new Error("Server Error: Invalid HMAC! Potential Attack!"); - } - } - var _seqnum = bb.readLong(); - var _machineid = bb.readLong(); - var numentries = bb.readInt8(); - - var _slot = new Slot(table, _seqnum, _machineid, prevhmac, hmac); - - for (var l = 0; l < numentries; l++) { - _slot.addShallowEntry(Entry.decode(_slot, bb)); - } - return _slot; - } - } - }]); - - return Slot; -}(); \ No newline at end of file diff --git a/src/js/iotjs/src/slotbuffer.js b/src/js/iotjs/src/slotbuffer.js deleted file mode 100644 index 9704852..0000000 --- a/src/js/iotjs/src/slotbuffer.js +++ /dev/null @@ -1,118 +0,0 @@ -"use strict"; - -var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); - -function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } - -var SlotBuffer = function () { - function SlotBuffer() { - _classCallCheck(this, SlotBuffer); - - this.DEFAULT_SIZE = 128; - this.array = []; - this.head = 0; - this.tail = 0; - this.oldestseqn = 0; - } - - _createClass(SlotBuffer, [{ - key: "size", - value: function size() { - if (this.head >= this.tail) { - return this.head - this.tail; - } - return this.array.length + this.head - this.tail; - } - }, { - key: "capacity", - value: function capacity() { - return this.array.length - 1; - } - }, { - key: "resize", - value: function resize(newsize) { - if (newsize === this.array.length - 1) { - return; - } - var newarray = []; - var currsize = this.size(); - var index = this.tail; - for (var i = 0; i < currsize; i++) { - newarray[i] = this.array[index]; - if (++index === this.array.length) { - index = 0; - } - this.array = newarray; - this.tail = 0; - this.head = currsize; - } - } - }, { - key: "incrementHead", - value: function incrementHead() { - this.head++; - if (this.head >= this.array.length) { - this.head = 0; - } - } - }, { - key: "incrementTail", - value: function incrementTail() { - this.tail++; - if (this.tail >= this.array.length) { - this.tail = 0; - } - } - }, { - key: "putSlot", - value: function putSlot(s) { - if (!(s instanceof Slot)) { - throw new Error("Error with arguments. Argument should be a slot object"); - } - this.array[this.head] = s; - this.incrementHead(); - - if (this.oldestseqn === 0) { - this.oldestseqn = s.getSequenceNumber(); - } - - if (this.head === this.tail) { - this.incrementTail(); - this.oldestseqn++; - } - } - }, { - key: "getSlot", - value: function getSlot(seqnum) { - var diff = seqnum - this.oldestseqn; - var index = diff + this.tail; - if (index >= this.array.length) { - if (this.head >= this.tail) { - return null; - } - index = index - this.array.length; - } - if (index >= this.array.length) { - return null; - } - - if (this.head >= this.tail && index >= this.head) { - return null; - } - - return this.array[index]; - } - }, { - key: "getOldestSeqNum", - value: function getOldestSeqNum() { - return this.oldestseqn; - } - }, { - key: "getNewestSeqNum", - value: function getNewestSeqNum() { - return this.oldestseqn + this.size() - 1; - } - }]); - - return SlotBuffer; -}(); \ No newline at end of file diff --git a/src/js/iotjs/src/slotindexer.js b/src/js/iotjs/src/slotindexer.js deleted file mode 100644 index 66f4b4d..0000000 --- a/src/js/iotjs/src/slotindexer.js +++ /dev/null @@ -1,39 +0,0 @@ -"use strict"; - -var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); - -function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } - -var SlotIndexer = function () { - function SlotIndexer(_updates, _buffer) { - _classCallCheck(this, SlotIndexer); - - // updates is an array of slot objects - // buffer is an instanceof slotbuffer constructor object in slotbuffer.js - this.updates = _updates; - if (_buffer && _buffer instanceof SlotBuffer) { - this.buffer = _buffer; - } else { - throw new Error("Argument error Buffer should be an instance of SlotBuffer"); - } - this.firstslotseqnum = this.updates[0].getSequenceNumber(); - } - - _createClass(SlotIndexer, [{ - key: "getSlot", - value: function getSlot(seqnum) { - if (seqnum >= this.firstslotseqnum) { - var offset = seqnum - this.firstslotseqnum; - if (offset >= this.updates.length) { - throw new Error('Invalid Slot Sequence Number Reference'); - } else { - return this.updates[offset]; - } - } else { - return this.buffer.getSlot(seqnum); - } - } - }]); - - return SlotIndexer; -}(); \ No newline at end of file diff --git a/src/js/iotjs/src/tablestatus.js b/src/js/iotjs/src/tablestatus.js deleted file mode 100644 index 64c14fc..0000000 --- a/src/js/iotjs/src/tablestatus.js +++ /dev/null @@ -1,66 +0,0 @@ -'use strict'; - -var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); - -function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } - -function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } - -function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } - -var TableStatus = function (_Entry) { - _inherits(TableStatus, _Entry); - - function TableStatus(slot, _maxslots) { - _classCallCheck(this, TableStatus); - - var _this = _possibleConstructorReturn(this, Object.getPrototypeOf(TableStatus).call(this, slot)); - - _this.maxslots = _maxslots; - return _this; - } - - _createClass(TableStatus, [{ - key: 'getMaxSlots', - value: function getMaxSlots() { - return this.maxslots; - } - }, { - key: 'encode', - value: function encode(bb) { - bb.writeByte(Entry.TypeTableStatus); - bb.writeInt8(this.maxslots); - } - }, { - key: 'getSize', - value: function getSize() { - return 4 + 1; - } - }, { - key: 'getType', - value: function getType() { - return Entry.TypeTableStatus; - } - }, { - key: 'getcopy', - value: function getcopy(s) { - if (!(s instanceof Slot)) { - throw new Error('Argument Error: s is not an instanceof Slot'); - } - return new TableStatus(s, this.maxslots); - } - }], [{ - key: 'decode', - value: function decode(slot, bb) { - //bb is an object of the type bytebuffer See main.js file and its require section - //for more details - if (!(bb instanceof ByteBuffer && slot instanceof Slot)) { - throw new Error('Argument Error: bb is not an instanceof Bytebuffer'); - } - this.maxslots = bb.readByte(); - return new TableStatus(slot, this.maxslots); - } - }]); - - return TableStatus; -}(Entry); \ No newline at end of file diff --git a/src/js/iotjs/test/test.js b/src/js/iotjs/test/test.js deleted file mode 100644 index 7d78e72..0000000 --- a/src/js/iotjs/test/test.js +++ /dev/null @@ -1,6 +0,0 @@ -var iot = require('../build/iotjs.js'); - -iot.baselinetest(); - - - diff --git a/src/script/C.cfg b/src/script/C.cfg deleted file mode 100644 index 6165d83..0000000 --- a/src/script/C.cfg +++ /dev/null @@ -1,37 +0,0 @@ -indent_with_tabs = 2 -indent_cmt_with_tabs = True -indent_columns = 2 -indent_class = True -output_tab_size = 2 -nl_if_brace = Remove -nl_brace_else = Remove -nl_elseif_brace = Remove -nl_struct_brace = Remove -nl_union_brace = Remove -nl_fcall_brace = Remove -nl_for_brace = Remove -nl_fdef_brace = Remove -nl_while_brace = Remove -nl_do_brace = Remove -nl_brace_while = Remove -nl_switch_brace = Remove -nl_before_case = True -nl_try_brace = Remove -nl_catch_brace = Remove -nl_brace_catch = Remove -sp_func_proto_paren = Remove -sp_func_def_paren = Remove -sp_inside_fparens = remove -sp_inside_fparen = remove -sp_func_call_paren = Remove -sp_fparen_brace = Add -sp_sparen_brace = Add -sp_paren_brace = Add -sp_else_brace = Add -sp_brace_else = Add -sp_catch_brace = Add -sp_brace_catch = Add -sp_try_brace = Add -sp_after_sparen = Add -sp_cond_colon = remove -sp_cond_question = remove diff --git a/src/script/java.cfg b/src/script/java.cfg deleted file mode 100644 index 6165d83..0000000 --- a/src/script/java.cfg +++ /dev/null @@ -1,37 +0,0 @@ -indent_with_tabs = 2 -indent_cmt_with_tabs = True -indent_columns = 2 -indent_class = True -output_tab_size = 2 -nl_if_brace = Remove -nl_brace_else = Remove -nl_elseif_brace = Remove -nl_struct_brace = Remove -nl_union_brace = Remove -nl_fcall_brace = Remove -nl_for_brace = Remove -nl_fdef_brace = Remove -nl_while_brace = Remove -nl_do_brace = Remove -nl_brace_while = Remove -nl_switch_brace = Remove -nl_before_case = True -nl_try_brace = Remove -nl_catch_brace = Remove -nl_brace_catch = Remove -sp_func_proto_paren = Remove -sp_func_def_paren = Remove -sp_inside_fparens = remove -sp_inside_fparen = remove -sp_func_call_paren = Remove -sp_fparen_brace = Add -sp_sparen_brace = Add -sp_paren_brace = Add -sp_else_brace = Add -sp_brace_else = Add -sp_catch_brace = Add -sp_brace_catch = Add -sp_try_brace = Add -sp_after_sparen = Add -sp_cond_colon = remove -sp_cond_question = remove diff --git a/src/script/makefile b/src/script/makefile deleted file mode 100644 index ac2da6e..0000000 --- a/src/script/makefile +++ /dev/null @@ -1,4 +0,0 @@ -tabbing: - uncrustify -c java.cfg --no-backup $$(find .. -name "*.java") - uncrustify -c C.cfg --no-backup $$(find .. -name "*.cpp") - uncrustify -c C.cfg --no-backup $$(find .. -name "*.h") diff --git a/src/server/.dir-locals.el b/src/server/.dir-locals.el deleted file mode 100644 index e166a2e..0000000 --- a/src/server/.dir-locals.el +++ /dev/null @@ -1,2 +0,0 @@ -((nil . ((indent-tabs-mode . t)))) - diff --git a/src/server/Makefile b/src/server/Makefile deleted file mode 100644 index 8eee1fa..0000000 --- a/src/server/Makefile +++ /dev/null @@ -1,15 +0,0 @@ -CPPFLAGS=-O0 -g -Wall - -all: iotcloud.fcgi - -iotcloud.fcgi: iotcloud.o iotquery.o - g++ $(CPPFLAGS) -o iotcloud.fcgi iotcloud.o iotquery.o -lfcgi -lfcgi++ - -iotcloud.o: iotcloud.cpp iotquery.h - g++ $(CPPFLAGS) -c -o iotcloud.o iotcloud.cpp - -iotquery.o: iotquery.cpp iotquery.h - g++ $(CPPFLAGS) -c -o iotquery.o iotquery.cpp - -clean: - rm *.o iotcloud.fcgi diff --git a/src/server/README.txt b/src/server/README.txt deleted file mode 100644 index 6eb138f..0000000 --- a/src/server/README.txt +++ /dev/null @@ -1,32 +0,0 @@ -1) Requires apache2 -2) Requires fastcgi (libapache2-mod-fastcgi and libfcgi-dev) - -Setup on ubuntu -1) Install modules - -2) Add .htaccess file in /var/www/html -RewriteEngine on -RewriteBase / -SetHandler cgi-script -RewriteRule ^([a-zA-Z0-9._]*\.iotcloud/([a-zA-Z0-9._]*))$ /cgi-bin/iotcloud.fcgi/$1 - -3) Create account directory. For example, create the directory test.iotcloud in /var/www/html - -- To password protect, create the following .htaccess file in the account directory: -AuthType Basic -AuthName "Private" -AuthUserFile /var/www/html/foo.iotcloud/.htpasswd -Require valid-user - -4) In apache2.conf, add to the /var/www directory section: -AllowOverride FileInfo AuthConfig - -5) In the sites-enabled/000-default.conf file, add the line: -SetEnv IOTCLOUD_ROOT /iotcloud/ - -6) Create the /iotcloud directory. - -7) Create the account directory in the /iotcloud directory. For example, test.iotcloud and give it permissions that the apache daemon can write to. - -8) Compile cloud server by typing make - -9) Copy it to the cgi-bin directory. diff --git a/src/server/iotcloud.cpp b/src/server/iotcloud.cpp deleted file mode 100644 index bb9eff8..0000000 --- a/src/server/iotcloud.cpp +++ /dev/null @@ -1,40 +0,0 @@ -#include -#include "iotquery.h" - -using namespace std; - - -int main(void) { - // Backup the stdio streambufs - streambuf * cin_streambuf = cin.rdbuf(); - streambuf * cout_streambuf = cout.rdbuf(); - streambuf * cerr_streambuf = cerr.rdbuf(); - - FCGX_Request request; - - FCGX_Init(); - FCGX_InitRequest(&request, 0, 0); - - while (FCGX_Accept_r(&request) == 0) { - fcgi_streambuf cin_fcgi_streambuf(request.in); - fcgi_streambuf cout_fcgi_streambuf(request.out); - fcgi_streambuf cerr_fcgi_streambuf(request.err); - - cin.rdbuf(&cin_fcgi_streambuf); - cout.rdbuf(&cout_fcgi_streambuf); - cerr.rdbuf(&cerr_fcgi_streambuf); - - IoTQuery * iotquery=new IoTQuery(&request); - iotquery->processQuery(); - - delete iotquery; - } - - // restore stdio streambufs - cin.rdbuf(cin_streambuf); - cout.rdbuf(cout_streambuf); - cerr.rdbuf(cerr_streambuf); - - return 0; -} - diff --git a/src/server/iotquery.cpp b/src/server/iotquery.cpp deleted file mode 100644 index 0b1c4b3..0000000 --- a/src/server/iotquery.cpp +++ /dev/null @@ -1,517 +0,0 @@ -#include "iotquery.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include - -using namespace std; - -const char * query_str="QUERY_STRING"; -const char * uri_str="REQUEST_URI"; -const char * method_str="REQUEST_METHOD"; -const char * iotcloudroot_str="IOTCLOUD_ROOT"; -const char * length_str="CONTENT_LENGTH"; - -IoTQuery::IoTQuery(FCGX_Request *request) : - request(request), - data(NULL), - directory(NULL), - uri(NULL), - query(NULL), - method(NULL), - iotcloudroot(NULL), - length(0), - oldestentry(0), - newestentry(0), - requestsequencenumber(0), - numqueueentries(DEFAULT_SIZE), - fd(-1), - reqGetSlot(false), - reqPutSlot(false), - reqSetSalt(false), - reqGetSalt(false) { -} - -IoTQuery::~IoTQuery() { - if (fd >= 0) - close(fd); - if (directory) - delete directory; - if (data) - delete data; -} - -/** - * Returns true if the account directory exists. - */ - -bool IoTQuery::checkDirectory() { - struct stat s; - int err=stat(directory, &s); - if (-1 == err) - return false; - return S_ISDIR(s.st_mode); -} - -/** - * Decodes query string from client. Extracts type of request, - * sequence number, and whether the request changes the number of - * slots. - */ - -void IoTQuery::decodeQuery() { - int len=strlen(query); - char * str=new char[len+1]; - memcpy(str, query, len+1); - char *tok_ptr=str; - - /* Parse commands */ - char *command=strsep(&tok_ptr, "&"); - if (strncmp(command, "req=putslot", 11) == 0) - reqPutSlot = true; - else if (strncmp(command, "req=getslot", 11) == 0) - reqGetSlot = true; - else if (strncmp(command, "req=setsalt", 11) == 0) - reqSetSalt = true; - else if (strncmp(command, "req=getsalt", 11) == 0) - reqGetSalt = true; - - /* Load Sequence Number for request */ - char *sequencenumber_str = strsep(&tok_ptr, "&"); - if (sequencenumber_str != NULL && - strncmp(sequencenumber_str, "seq=", 4) == 0) { - sequencenumber_str = strchr(sequencenumber_str, '='); - if (sequencenumber_str != NULL) { - requestsequencenumber = strtoll(sequencenumber_str + 1, NULL, 10); - } - } - - /* don't allow a really old sequence number */ - if (requestsequencenumber < oldestentry) - requestsequencenumber = oldestentry; - - /* Update size if we get request */ - char * numqueueentries_str = tok_ptr; - if (numqueueentries_str != NULL && - strncmp(numqueueentries_str, "max=", 4) == 0) { - numqueueentries_str = strchr(numqueueentries_str, '=') + 1; - numqueueentries = strtoll(numqueueentries_str, NULL, 10); - } - - delete str; -} - -/** - * Helper function to write data to file. - */ - -void doWrite(int fd, char *data, long long length) { - long long offset=0; - do { - long long byteswritten=write(fd, &data[offset], length); - if (byteswritten > 0) { - length -= byteswritten; - offset += byteswritten; - } else { - cerr << "Bytes not written" << endl; - if (byteswritten < 0) { - cerr << strerror(errno) << " error writing slot file" << endl; - } - return; - } - } while(length != 0); -} - -/** Helper function to read data from file. */ -bool doRead(int fd, void *buf, int numbytes) { - int offset=0; - char *ptr=(char *)buf; - do { - int bytesread=read(fd, ptr+offset, numbytes); - if (bytesread > 0) { - offset += bytesread; - numbytes -= bytesread; - } else - return false; - } while (numbytes!=0); - return true; -} - -/** - * Function that handles a getSlot request. - */ - -void IoTQuery::getSlot() { - int numrequeststosend = (int)((newestentry-requestsequencenumber)+1); - if (numrequeststosend < 0) - numrequeststosend = 0; - long long numbytes = 0; - int filesizes[numrequeststosend]; - int fdarray[numrequeststosend]; - int index=0; - for(long long seqn = requestsequencenumber; seqn <= newestentry; seqn++, index++) { - struct stat st; - char *filename=getSlotFileName(seqn); - if (stat(filename, &st) == 0) { - fdarray[index]=open(filename, O_RDONLY); - filesizes[index]=st.st_size; - numbytes+=filesizes[index]; - } else { - fdarray[index]=-1; - filesizes[index]=0; - } - delete filename; - } - const char header[]="getslot"; - - /* Size is the header + the payload + space for number of requests - plus sizes of each slot */ - - long long size=sizeof(header)-1+sizeof(numrequeststosend)+4*numrequeststosend+numbytes; - char * response = new char[size]; - long long offset=0; - memcpy(response, header, sizeof(header)-1); - offset+=sizeof(header)-1; - int numreq=htonl(numrequeststosend); - memcpy(response + offset, &numreq, sizeof(numreq)); - offset+=sizeof(numrequeststosend); - for(int i=0; i=0) { - doRead(fdarray[i], response+offset, filesizes[i]); - offset+=filesizes[i]; - } - } - - /* Send the response out to the webserver. */ - sendResponse(response, size); - - /* Delete the response buffer and close the files. */ - delete response; - for(int i=0; i= 0) - close(fdarray[i]); - } -} - -/** - * The method setSalt handles a setSalt request from the client. - */ - -void IoTQuery::setSalt() { - /* Write the slot data we received to a SLOT file */ - char *filename = getSaltFileName(); - int saltfd = open(filename, O_CREAT|O_WRONLY, S_IRUSR| S_IWUSR); - doWrite(saltfd, data, length); - char response[0]; - sendResponse(response, 0); - close(saltfd); - delete filename; -} - -/** - * The method getSalt handles a setSalt request from the client. - */ - -void IoTQuery::getSalt() { - /* Write the slot data we received to a SLOT file */ - char *filename = getSaltFileName(); - int filesize = 0; - struct stat st; - if (stat(filename, &st) == 0) { - filesize=st.st_size; - } else { - delete filename; - return; - } - int saltfd = open(filename, O_RDONLY); - int responsesize = filesize + sizeof(int); - char * response = new char[responsesize]; - doRead(saltfd, response+ sizeof(int), filesize); - int n_filesize=htonl(filesize); - *((int*) response) = n_filesize; - sendResponse(response, responsesize); - close(saltfd); - delete filename; - delete response; -} - -/** - * The method putSlot handles a putSlot request from the client - */ - -void IoTQuery::putSlot() { - /* Check if the request is stale and send update in that case. This - servers as an implicit failure of the request. */ - if (requestsequencenumber!=(newestentry+1)) { - getSlot(); - return; - } - - /* See if we have too many slots and if so, delete the old one */ - int numberofliveslots=(int) ((newestentry-oldestentry)+1); - if (numberofliveslots >= numqueueentries) { - removeOldestSlot(); - } - - /* Write the slot data we received to a SLOT file */ - char *filename = getSlotFileName(requestsequencenumber); - int slotfd = open(filename, O_CREAT|O_WRONLY, S_IRUSR| S_IWUSR); - doWrite(slotfd, data, length); - close(slotfd); - delete filename; - newestentry = requestsequencenumber; - - /* Update the seuqence numbers and other status file information. */ - updateStatusFile(); - - /* Send response acknowledging success */ - char command[]="putslot"; - sendResponse(command, sizeof(command)-1); -} - -/** - * Method sends response. It wraps in appropriate headers for web - * server. - */ - -void IoTQuery::sendResponse(char * bytes, int len) { - cout << "Accept-Ranges: bytes\r\n" - << "Content-Length: " << len << "\r\n" - << "\r\n"; - cout.write(bytes, len); -} - -/** - * Computes the name for a slot file for the given sequence number. - */ - -char * IoTQuery::getSlotFileName(long long seqnum) { - int directorylen=strlen(directory); - - /* Size is 19 digits for ASCII representation of a long + 4 - characters for SLOT string + 1 character for null termination + - directory size*/ - - char * filename=new char[25+directorylen]; - snprintf(filename, 25+directorylen, "%s/SLOT%lld", directory, seqnum); - return filename; -} - -/** - * Computes the name for a salt file - */ - -char * IoTQuery::getSaltFileName() { - int directorylen=strlen(directory); - - /* Size is 4 characters for SALT string + 1 character for null - termination + directory size*/ - - char * filename=new char[6+directorylen]; - snprintf(filename, 6+directorylen, "%s/SALT", directory); - return filename; -} - -/** - * Removes the oldest slot file - */ - -void IoTQuery::removeOldestSlot() { - if (oldestentry!=0) { - char * filename=getSlotFileName(oldestentry); - unlink(filename); - delete filename; - } - oldestentry++; -} - -/** - * Processes the query sent to the fastcgi handler. - */ - -void IoTQuery::processQuery() { - getQuery(); - getDirectory(); - readData(); - - /* Verify that we receive a post request. */ - if (strncmp(method, "POST", 4) != 0) { - cerr << "Not POST Request" << endl; - return; - } - - /* Make sure the directory is okay. */ - if (directory == NULL || - !checkDirectory()) { - cerr << "Directory " << directory << " does not exist" << endl; - return; - } - - /* Get queue state from the status file. If it doesn't exist, - create it. */ - if (!openStatusFile()) { - cerr << "Failed to open status file" << endl; - return; - } - - /* Lock status file to keep other requests out. */ - flock(fd, LOCK_EX); - - /* Decode query. */ - decodeQuery(); - - /* Handle request. */ - if (reqGetSlot) - getSlot(); - else if (reqPutSlot) - putSlot(); - else if (reqSetSalt) - setSalt(); - else if (reqGetSalt) - getSalt(); - else { - cerr << "No recognized request" << endl; - return; - } -} - -/** - * Reads in data for request. This is used for the slot to be - * inserted. - */ - -void IoTQuery::readData() { - if (length) { - data = new char[length+1]; - memset(data, 0, length+1); - cin.read(data, length); - } - do { - char dummy; - cin >> dummy; - } while (!cin.eof()); -} - - -/** - * Reads relevant environmental variables to find out the request. - */ - -void IoTQuery::getQuery() { - uri = FCGX_GetParam(uri_str, request->envp); - query = FCGX_GetParam(query_str, request->envp); - method = FCGX_GetParam(method_str, request->envp); - iotcloudroot = FCGX_GetParam(iotcloudroot_str, request->envp); - - /** We require the content-length header to be sent. */ - char * reqlength = FCGX_GetParam(length_str, request->envp); - if (reqlength) { - length=strtoll(reqlength, NULL, 10); - } else { - length=0; - } -} - -/** - * Initializes directory field from environmental variables. - */ - -void IoTQuery::getDirectory() { - char * split = strchr((char *)uri, '?'); - if (split == NULL) - return; - int split_len = (int) (split-uri); - int rootdir_len = strlen(iotcloudroot); - int directory_len = split_len + rootdir_len + 1; - directory = new char[directory_len]; - memcpy(directory, iotcloudroot, rootdir_len); - memcpy(directory + rootdir_len, uri, split_len); - directory[directory_len-1]=0; -} - -/** - * Helper function that is used to read the status file. - */ - -int doread(int fd, void *ptr, size_t count, off_t offset) { - do { - size_t bytesread=pread(fd, ptr, count, offset); - if (bytesread==count) { - return 1; - } else if (bytesread==0) { - return 0; - } - } while(1); -} - - -/** - * Writes the current state to the status file. - */ - -void IoTQuery::updateStatusFile() { - pwrite(fd, &numqueueentries, sizeof(numqueueentries), OFFSET_MAX); - pwrite(fd, &oldestentry, sizeof(oldestentry), OFFSET_OLD); - pwrite(fd, &newestentry, sizeof(newestentry), OFFSET_NEW); -} - -/** - * Reads in queue state from the status file. Returns true if - * successful. - */ - -bool IoTQuery::openStatusFile() { - char statusfile[]="queuestatus"; - int len=strlen(directory); - - char * filename=new char[len+sizeof(statusfile)+2]; - memcpy(filename, directory, len); - filename[len]='/'; - memcpy(filename+len+1, statusfile, sizeof(statusfile)); - filename[len+sizeof(statusfile)+1]=0; - fd=open(filename, O_CREAT| O_RDWR, S_IRUSR| S_IWUSR); - delete filename; - - if (fd < 0) { - cerr << strerror(errno) << " error opening statusfile" << endl; - return false; - } - - /* Read in queue size, oldest sequence number, and newest sequence number. */ - int size; - int needwrite=0; - if (doread(fd, &size, sizeof(size), OFFSET_MAX)) - numqueueentries=size; - else - needwrite=1; - - long long entry; - if (doread(fd, &entry, sizeof(entry), OFFSET_OLD)) - oldestentry=entry; - else - needwrite=1; - - if (doread(fd, &entry, sizeof(entry), OFFSET_NEW)) - newestentry=entry; - else - needwrite=1; - - if (needwrite) - updateStatusFile(); - - return true; -} - - diff --git a/src/server/iotquery.h b/src/server/iotquery.h deleted file mode 100644 index ae39366..0000000 --- a/src/server/iotquery.h +++ /dev/null @@ -1,68 +0,0 @@ -#ifndef IOTQUERY_H -#define IOTQUERY_H -#include -#include "fcgio.h" -#include "fcgi_stdio.h" - -#define DEFAULT_SIZE 128 -#define OFFSET_MAX 0 -#define OFFSET_OLD 4 -#define OFFSET_NEW 12 - -class IoTQuery { -public: - IoTQuery(FCGX_Request * request); - ~IoTQuery(); - void processQuery(); - -private: - void sendResponse(char *data, int length); - void getQuery(); - void getDirectory(); - void readData(); - bool checkDirectory(); - bool openStatusFile(); - void updateStatusFile(); - void decodeQuery(); - void getSlot(); - void putSlot(); - void setSalt(); - void getSalt(); - void removeOldestSlot(); - char * getSlotFileName(long long); - char * getSaltFileName(); - - FCGX_Request * request; - char *data; - /* Directory slot files are placed in. */ - char *directory; - /* Full URI from Apache */ - const char * uri; - /* Query portion of URI */ - const char * query; - /* Type of request: GET or PUT */ - const char * method; - /* Root directory for all accounts */ - const char * iotcloudroot; - /* Expected length of data from client */ - long long length; - /* Sequence number for oldest slot */ - long long oldestentry; - /* Sequence number for newest slot */ - long long newestentry; - /* Sequence number from request */ - long long requestsequencenumber; - /* Size of queue */ - int numqueueentries; - /* fd for queuestatus file */ - int fd; - /* Is the request to get a slot? */ - bool reqGetSlot; - /* Is the request to put a slot? */ - bool reqPutSlot; - /* Is the request to set the salt? */ - bool reqSetSalt; - /* Is the request to get the salt? */ - bool reqGetSalt; -}; -#endif diff --git a/src2/java/.dir-locals.el b/src2/java/.dir-locals.el deleted file mode 100644 index e166a2e..0000000 --- a/src2/java/.dir-locals.el +++ /dev/null @@ -1,2 +0,0 @@ -((nil . ((indent-tabs-mode . t)))) - diff --git a/src2/java/iotcloud/Abort.java b/src2/java/iotcloud/Abort.java deleted file mode 100644 index 4d0c59b..0000000 --- a/src2/java/iotcloud/Abort.java +++ /dev/null @@ -1,53 +0,0 @@ -package iotcloud; - -import java.nio.ByteBuffer; - -/** - * This Entry records the abort sent by a given machine. - * @author Ali Younis - * @version 1.0 - */ - - -class Abort extends Entry { - private long seqnumtrans; - private long machineid; - - Abort(Slot slot, long _seqnumtrans, long _machineid) { - super(slot); - seqnumtrans=_seqnumtrans; - machineid=_machineid; - } - - long getMachineID() { - return machineid; - } - - long getTransSequenceNumber() { - return seqnumtrans; - } - - static Entry decode(Slot slot, ByteBuffer bb) { - long seqnumtrans=bb.getLong(); - long machineid=bb.getLong(); - return new Abort(slot, seqnumtrans, machineid); - } - - void encode(ByteBuffer bb) { - bb.put(Entry.TypeAbort); - bb.putLong(seqnumtrans); - bb.putLong(machineid); - } - - int getSize() { - return (2 * Long.BYTES) + Byte.BYTES; - } - - byte getType() { - return Entry.TypeAbort; - } - - Entry getCopy(Slot s) { - return new Abort(s, seqnumtrans, machineid); - } -} \ No newline at end of file diff --git a/src2/java/iotcloud/CloudComm.java b/src2/java/iotcloud/CloudComm.java deleted file mode 100644 index f38756d..0000000 --- a/src2/java/iotcloud/CloudComm.java +++ /dev/null @@ -1,235 +0,0 @@ -package iotcloud; -import java.io.*; -import java.net.*; -import java.util.Arrays; -import javax.crypto.*; -import javax.crypto.spec.*; -import java.security.SecureRandom; - -/** - * This class provides a communication API to the webserver. It also - * validates the HMACs on the slots and handles encryption. - * @author Brian Demsky - * @version 1.0 - */ - - -class CloudComm { - String baseurl; - Cipher encryptCipher; - Cipher decryptCipher; - Mac mac; - String password; - SecureRandom random; - static final int SALT_SIZE = 8; - byte salt[]; - Table table; - - /** - * Empty Constructor needed for child class. - */ - - CloudComm() { - } - - /** - * Constructor for actual use. Takes in the url and password. - */ - - CloudComm(Table _table, String _baseurl, String _password) { - this.table = _table; - this.baseurl = _baseurl; - this.password = _password; - this.random = new SecureRandom(); - } - - /** - * Generates Key from password. - */ - - private SecretKeySpec initKey() { - try { - PBEKeySpec keyspec = new PBEKeySpec(password.toCharArray(), salt, 65536, 128); - SecretKey tmpkey = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256").generateSecret(keyspec); - return new SecretKeySpec(tmpkey.getEncoded(), "AES"); - } catch (Exception e) { - e.printStackTrace(); - throw new Error("Failed generating key."); - } - } - - /** - * Inits the HMAC generator. - */ - - private void initCrypt() { - try { - SecretKeySpec key = initKey(); - password = null; // drop password - mac = Mac.getInstance("HmacSHA256"); - mac.init(key); - encryptCipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); - encryptCipher.init(Cipher.ENCRYPT_MODE, key); - decryptCipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); - decryptCipher.init(Cipher.DECRYPT_MODE, key); - } catch (Exception e) { - e.printStackTrace(); - throw new Error("Failed To Initialize Ciphers"); - } - } - - /* - * Builds the URL for the given request. - */ - - private URL buildRequest(boolean isput, long sequencenumber, long maxentries) throws IOException { - String reqstring = isput ? "req=putslot" : "req=getslot"; - String urlstr = baseurl + "?" + reqstring + "&seq=" + sequencenumber; - if (maxentries != 0) - urlstr += "&max=" + maxentries; - return new URL(urlstr); - } - - public void setSalt() { - try { - salt = new byte[SALT_SIZE]; - random.nextBytes(salt); - URL url = new URL(baseurl + "?req=setsalt"); - URLConnection con = url.openConnection(); - HttpURLConnection http = (HttpURLConnection) con; - http.setRequestMethod("POST"); - http.setFixedLengthStreamingMode(salt.length); - http.setDoOutput(true); - http.connect(); - OutputStream os = http.getOutputStream(); - os.write(salt); - int responsecode = http.getResponseCode(); - if (responsecode != HttpURLConnection.HTTP_OK) { - // TODO: Remove this print - System.out.println(responsecode); - throw new Error("Invalid response"); - } - } catch (Exception e) { - e.printStackTrace(); - throw new Error("Failed setting salt"); - } - initCrypt(); - } - - private void getSalt() throws Exception { - URL url = new URL(baseurl + "?req=getsalt"); - URLConnection con = url.openConnection(); - HttpURLConnection http = (HttpURLConnection) con; - http.setRequestMethod("POST"); - http.connect(); - - InputStream is = http.getInputStream(); - DataInputStream dis = new DataInputStream(is); - int salt_length = dis.readInt(); - byte [] tmp = new byte[salt_length]; - dis.readFully(tmp); - salt = tmp; - } - - /* - * API for putting a slot into the queue. Returns null on success. - * On failure, the server will send slots with newer sequence - * numbers. - */ - - Slot[] putSlot(Slot slot, int max) { - try { - if (salt == null) { - getSalt(); - initCrypt(); - } - - long sequencenumber = slot.getSequenceNumber(); - byte[] bytes = slot.encode(mac); - bytes = encryptCipher.doFinal(bytes); - - URL url = buildRequest(true, sequencenumber, max); - URLConnection con = url.openConnection(); - HttpURLConnection http = (HttpURLConnection) con; - - http.setRequestMethod("POST"); - http.setFixedLengthStreamingMode(bytes.length); - http.setDoOutput(true); - http.connect(); - - OutputStream os = http.getOutputStream(); - os.write(bytes); - - InputStream is = http.getInputStream(); - DataInputStream dis = new DataInputStream(is); - byte[] resptype = new byte[7]; - dis.readFully(resptype); - if (Arrays.equals(resptype, "getslot".getBytes())) - return processSlots(dis); - else if (Arrays.equals(resptype, "putslot".getBytes())) - return null; - else - throw new Error("Bad response to putslot"); - } catch (Exception e) { - e.printStackTrace(); - throw new Error("putSlot failed"); - } - } - - /** - * Request the server to send all slots with the given - * sequencenumber or newer. - */ - - Slot[] getSlots(long sequencenumber) { - try { - if (salt == null) { - getSalt(); - initCrypt(); - } - - URL url = buildRequest(false, sequencenumber, 0); - URLConnection con = url.openConnection(); - HttpURLConnection http = (HttpURLConnection) con; - http.setRequestMethod("POST"); - http.connect(); - InputStream is = http.getInputStream(); - - DataInputStream dis = new DataInputStream(is); - - byte[] resptype = new byte[7]; - dis.readFully(resptype); - if (!Arrays.equals(resptype, "getslot".getBytes())) - throw new Error("Bad Response: " + new String(resptype)); - else - return processSlots(dis); - } catch (Exception e) { - e.printStackTrace(); - throw new Error("getSlots failed"); - } - } - - /** - * Method that actually handles building Slot objects from the - * server response. Shared by both putSlot and getSlots. - */ - - private Slot[] processSlots(DataInputStream dis) throws Exception { - int numberofslots = dis.readInt(); - int[] sizesofslots = new int[numberofslots]; - Slot[] slots = new Slot[numberofslots]; - for (int i = 0; i < numberofslots; i++) - sizesofslots[i] = dis.readInt(); - - for (int i = 0; i < numberofslots; i++) { - byte[] data = new byte[sizesofslots[i]]; - dis.readFully(data); - - data = decryptCipher.doFinal(data); - - slots[i] = Slot.decode(table, data, mac); - } - dis.close(); - return slots; - } -} diff --git a/src2/java/iotcloud/Commit.java b/src2/java/iotcloud/Commit.java deleted file mode 100644 index 1ee044d..0000000 --- a/src2/java/iotcloud/Commit.java +++ /dev/null @@ -1,102 +0,0 @@ -package iotcloud; - -import java.nio.ByteBuffer; -import java.util.Set; -import java.util.HashSet; -import java.util.Iterator; - -/** - * This Entry records the commit of a transaction. - * @author Ali Younis - * @version 1.0 - */ - - -class Commit extends Entry { - private long seqnumtrans; - private Set keyValueUpdateSet = null; - - - public Commit(Slot slot, long _seqnumtrans, Set _keyValueUpdateSet) { - super(slot); - seqnumtrans = _seqnumtrans; - - keyValueUpdateSet = new HashSet(); - - for (KeyValue kv : _keyValueUpdateSet) { - KeyValue kvCopy = kv.getCopy(); - keyValueUpdateSet.add(kvCopy); - } - } - - public long getTransSequenceNumber() { - return seqnumtrans; - } - - public Set getkeyValueUpdateSet() { - return keyValueUpdateSet; - } - - public byte getType() { - return Entry.TypeCommit; - } - - public int getSize() { - int size = Long.BYTES + Byte.BYTES; // seq id, entry type - size += Integer.BYTES; // number of KV's - - // Size of each KV - for (KeyValue kv : keyValueUpdateSet) { - size += kv.getSize(); - } - - return size; - } - - static Entry decode(Slot slot, ByteBuffer bb) { - long seqnumtrans = bb.getLong(); - int numberOfKeys = bb.getInt(); - - Set kvSet = new HashSet(); - for (int i = 0; i < numberOfKeys; i++) { - KeyValue kv = KeyValue.decode(bb); - kvSet.add(kv); - } - - return new Commit(slot, seqnumtrans, kvSet); - } - - public void encode(ByteBuffer bb) { - bb.put(Entry.TypeCommit); - bb.putLong(seqnumtrans); - bb.putInt(keyValueUpdateSet.size()); - - for (KeyValue kv : keyValueUpdateSet) { - kv.encode(bb); - } - } - - public Entry getCopy(Slot s) { - return new Commit(s, seqnumtrans, keyValueUpdateSet); - } - - public void updateLiveKeys(Set kvSet) { - - if (!this.isLive()) - return; - - for (KeyValue kv1 : kvSet) { - for (Iterator i = keyValueUpdateSet.iterator(); i.hasNext();) { - KeyValue kv2 = i.next(); - - if (kv1.getKey() == kv2.getKey()) { - keyValueUpdateSet.remove(kv2); - break; - } - } - } - - if (keyValueUpdateSet.size() == 0) - this.setDead(); - } -} \ No newline at end of file diff --git a/src2/java/iotcloud/Entry.java b/src2/java/iotcloud/Entry.java deleted file mode 100644 index c5a6807..0000000 --- a/src2/java/iotcloud/Entry.java +++ /dev/null @@ -1,116 +0,0 @@ -package iotcloud; -import java.nio.ByteBuffer; - -/** - * Generic class that wraps all the different types of information - * that can be stored in a Slot. - * @author Brian Demsky - * @version 1.0 - */ - -abstract class Entry implements Liveness { - - - static final byte TypeCommit = 1; - static final byte TypeAbort = 2; - static final byte TypeTransaction = 3; - static final byte TypeNewKey = 4; - static final byte TypeLastMessage = 5; - static final byte TypeRejectedMessage = 6; - static final byte TypeTableStatus = 7; - - - - /* Records whether the information is still live or has been - superceded by a newer update. */ - - private boolean islive = true; - private Slot parentslot; - - public Entry(Slot _parentslot) { - parentslot = _parentslot; - } - - /** - * Static method for decoding byte array into Entry objects. First - * byte tells the type of entry. - */ - - static Entry decode(Slot slot, ByteBuffer bb) { - byte type = bb.get(); - switch (type) { - - case TypeCommit: - return Commit.decode(slot, bb); - - case TypeAbort: - return Abort.decode(slot, bb); - - case TypeTransaction: - return Transaction.decode(slot, bb); - - case TypeNewKey: - return NewKey.decode(slot, bb); - - case TypeLastMessage: - return LastMessage.decode(slot, bb); - - case TypeRejectedMessage: - return RejectedMessage.decode(slot, bb); - - case TypeTableStatus: - return TableStatus.decode(slot, bb); - - default: - throw new Error("Unrecognized Entry Type: " + type); - } - } - - /** - * Returns true if the Entry object is still live. - */ - - public boolean isLive() { - return islive; - } - - /** - * Flags the entry object as dead. Also decrements the live count - * of the parent slot. - */ - - public void setDead() { - - if (!islive ) { - return; // already dead - } - - islive = false; - parentslot.decrementLiveCount(); - } - - /** - * Serializes the Entry object into the byte buffer. - */ - - abstract void encode(ByteBuffer bb); - - /** - * Returns the size in bytes the entry object will take in the byte - * array. - */ - - abstract int getSize(); - - /** - * Returns a byte encoding the type of the entry object. - */ - - abstract byte getType(); - - /** - * Returns a copy of the Entry that can be added to a different slot. - */ - abstract Entry getCopy(Slot s); - -} diff --git a/src2/java/iotcloud/Guard.java b/src2/java/iotcloud/Guard.java deleted file mode 100644 index c08ed28..0000000 --- a/src2/java/iotcloud/Guard.java +++ /dev/null @@ -1,124 +0,0 @@ -package iotcloud; - -import java.util.Set; -import java.util.HashSet; -import java.nio.ByteBuffer; - -import javax.script.ScriptEngine; -import javax.script.ScriptEngineManager; -import javax.script.ScriptException; -import java.lang.NullPointerException; - - -class Guard { - - static final byte Equal = 1; - static final byte NotEqual = 2; - - private IoTString booleanExpression; - - public Guard() { - booleanExpression = null; - } - - public Guard(IoTString _booleanExpression) { - booleanExpression = _booleanExpression; - } - - /** - * Create an equality expression for a key value. - * - */ - public static String createExpression(IoTString keyName, IoTString keyValue, byte op) { - if (op == Equal) { - return keyName.toString() + "=='" + keyValue.toString() + "'"; - } else if (op == NotEqual) { - return keyName.toString() + "!='" + keyValue.toString() + "'"; - } - - // Unrecognized op - return null; - } - - /** - * Add a boolean expression to the guard. - * - */ - public void setGuardExpression(String expr) { - booleanExpression = new IoTString(expr); - } - - /** - * Evaluate the guard expression for a given set of key value pairs. - * - */ - public boolean evaluate(Set kvSet) throws ScriptException, NullPointerException { - - // There are no conditions to evaluate - if (booleanExpression == null) { - return true; - } - - // All the current key value pairs that we need to evaluate the condition - String[] variables = new String[kvSet.size()]; - - // Fill the variables array - int i = 0; - for (KeyValue kv : kvSet) { - variables[i] = kv.getKey() + " ='" + kv.getValue() + "'"; - i++; - } - - // Prep the evaluation engine (script engine) - ScriptEngine engine = new ScriptEngineManager().getEngineByName("JavaScript"); - for (String s : variables) { - engine.eval(s); - } - - // Evaluate the guard condition - return 1 == (Integer)engine.eval(booleanExpression.toString()); - } - - /** - * Get the size of the guard condition - * - */ - public int getSize() { - - if (booleanExpression == null) { - return Integer.BYTES; - } - - return Integer.BYTES + booleanExpression.length(); - } - - public void encode(ByteBuffer bb) { - if (booleanExpression == null) { - bb.putInt(0); - } else { - bb.putInt(booleanExpression.length()); - bb.put(booleanExpression.internalBytes()); - } - } - - static Guard decode(ByteBuffer bb) { - int exprLength = bb.getInt(); - - if (exprLength != 0) { - byte[] expr = new byte[exprLength]; - bb.get(expr); - return new Guard(IoTString.shallow(expr)); - } - return new Guard(null); - } - - public Guard getCopy() { - - if (booleanExpression == null) { - return new Guard(null); - } - - return new Guard(IoTString.shallow(booleanExpression.internalBytes())); - } - -} \ No newline at end of file diff --git a/src2/java/iotcloud/IoTString.java b/src2/java/iotcloud/IoTString.java deleted file mode 100644 index 83a3fa1..0000000 --- a/src2/java/iotcloud/IoTString.java +++ /dev/null @@ -1,105 +0,0 @@ -package iotcloud; - -import java.util.Arrays; - -/** - * IoTString is wraps the underlying byte string. We don't use the - * standard String class as we have bytes and not chars. - * @author Brian Demsky - * @version 1.0 - */ - - -final public class IoTString { - byte[] array; - int hashcode; - - private IoTString() { - } - - /** - * Builds an IoTString object around the byte array. This - * constructor makes a copy, so the caller is free to modify the byte array. - */ - - public IoTString(byte[] _array) { - array=(byte[]) _array.clone(); - hashcode=Arrays.hashCode(array); - } - - /** - * Converts the String object to a byte representation and stores it - * into the IoTString object. - */ - - public IoTString(String str) { - array=str.getBytes(); - hashcode=Arrays.hashCode(array); - } - - /** - * Internal methods to build an IoTString using the byte[] passed - * in. Caller is responsible for ensuring the byte[] is never - * modified. - */ - - static IoTString shallow(byte[] _array) { - IoTString i=new IoTString(); - i.array = _array; - i.hashcode = Arrays.hashCode(_array); - return i; - } - - /** - * Internal method to grab a reference to our byte array. Caller - * must not modify it. - */ - - byte[] internalBytes() { - return array; - } - - /** - * Returns the hashCode as computed by Arrays.hashcode(byte[]). - */ - - public int hashCode() { - return hashcode; - } - - /** - * Returns a String representation of the IoTString. - */ - - public String toString() { - return new String(array); - } - - /** - * Returns a copy of the underlying byte string. - */ - - public byte[] getBytes() { - return (byte[]) array.clone(); - } - - /** - * Returns true if two byte strings have the same content. - */ - - public boolean equals(Object o) { - if (o instanceof IoTString) { - IoTString i=(IoTString)o; - return Arrays.equals(array, i.array); - } - return false; - } - - /** - * Returns the length in bytes of the IoTString. - */ - - public int length() { - return array.length; - } -} diff --git a/src2/java/iotcloud/KeyValue.java b/src2/java/iotcloud/KeyValue.java deleted file mode 100644 index 79b9e60..0000000 --- a/src2/java/iotcloud/KeyValue.java +++ /dev/null @@ -1,55 +0,0 @@ -package iotcloud; -import java.nio.ByteBuffer; - -/** - * KeyValue entry for Slot. - * @author Brian Demsky - * @version 1.0 - */ - -class KeyValue { /*extends Entry */ - private IoTString key; - private IoTString value; - - public KeyValue(IoTString _key, IoTString _value) { - key = _key; - value = _value; - } - - public IoTString getKey() { - return key; - } - - public IoTString getValue() { - return value; - } - - static KeyValue decode(ByteBuffer bb) { - int keylength = bb.getInt(); - int valuelength = bb.getInt(); - byte[] key = new byte[keylength]; - byte[] value = new byte[valuelength]; - bb.get(key); - bb.get(value); - return new KeyValue(IoTString.shallow(key), IoTString.shallow(value)); - } - - public void encode(ByteBuffer bb) { - bb.putInt(key.length()); - bb.putInt(value.length()); - bb.put(key.internalBytes()); - bb.put(value.internalBytes()); - } - - public int getSize() { - return 2 * Integer.BYTES + key.length() + value.length(); - } - - public String toString() { - return value.toString(); - } - - public KeyValue getCopy() { - return new KeyValue(key, value); - } -} diff --git a/src2/java/iotcloud/LastMessage.java b/src2/java/iotcloud/LastMessage.java deleted file mode 100644 index 738dff6..0000000 --- a/src2/java/iotcloud/LastMessage.java +++ /dev/null @@ -1,55 +0,0 @@ -package iotcloud; - -import java.nio.ByteBuffer; - -/** - * This Entry records the last message sent by a given machine. - * @author Brian Demsky - * @version 1.0 - */ - - -class LastMessage extends Entry { - private long machineid; - private long seqnum; - - public LastMessage(Slot slot, long _machineid, long _seqnum) { - super(slot); - machineid=_machineid; - seqnum=_seqnum; - } - - public long getMachineID() { - return machineid; - } - - public long getSequenceNumber() { - return seqnum; - } - - static Entry decode(Slot slot, ByteBuffer bb) { - long machineid=bb.getLong(); - long seqnum=bb.getLong(); - return new LastMessage(slot, machineid, seqnum); - } - - public void encode(ByteBuffer bb) { - bb.put(Entry.TypeLastMessage); - bb.putLong(machineid); - bb.putLong(seqnum); - } - - public int getSize() { - return 2*Long.BYTES+Byte.BYTES; - } - - public byte getType() { - return Entry.TypeLastMessage; - } - - public Entry getCopy(Slot s) { - return new LastMessage(s, machineid, seqnum); - } -} - - diff --git a/src2/java/iotcloud/Liveness.java b/src2/java/iotcloud/Liveness.java deleted file mode 100644 index 2c840e4..0000000 --- a/src2/java/iotcloud/Liveness.java +++ /dev/null @@ -1,11 +0,0 @@ -package iotcloud; - -/** - * Interface common to both classes that record information about the - * last message sent by a machine. (Either a Slot or a LastMessage. - * @author Brian Demsky - * @version 1.0 - */ - -interface Liveness { -} diff --git a/src2/java/iotcloud/Makefile b/src2/java/iotcloud/Makefile deleted file mode 100644 index 2d45b63..0000000 --- a/src2/java/iotcloud/Makefile +++ /dev/null @@ -1,17 +0,0 @@ -all: server - -JAVAC = javac -JAVADOC = javadoc -BIN_DIR = bin -DOCS_DIR = docs - -server: - $(JAVAC) -d $(BIN_DIR) *.java - -doc: server - $(JAVADOC) -private -d $(DOCS_DIR) *.java - -clean: - rm -r bin/* - rm -r docs/* - rm *~ diff --git a/src2/java/iotcloud/NewKey.java b/src2/java/iotcloud/NewKey.java deleted file mode 100644 index 0970016..0000000 --- a/src2/java/iotcloud/NewKey.java +++ /dev/null @@ -1,57 +0,0 @@ -package iotcloud; - -import java.nio.ByteBuffer; - -/** - * This Entry records the abort sent by a given machine. - * @author Ali Younis - * @version 1.0 - */ - - -class NewKey extends Entry { - private IoTString key; - private long machineid; - - public NewKey(Slot slot, IoTString _key, long _machineid) { - super(slot); - key = _key; - machineid = _machineid; - } - - public long getMachineID() { - return machineid; - } - - public IoTString getKey() { - return key; - } - - static Entry decode(Slot slot, ByteBuffer bb) { - int keylength = bb.getInt(); - byte[] key = new byte[keylength]; - bb.get(key); - long machineid = bb.getLong(); - - return new NewKey(slot, IoTString.shallow(key), machineid); - } - - public void encode(ByteBuffer bb) { - bb.put(Entry.TypeNewKey); - bb.putInt(key.length()); - bb.put(key.internalBytes()); - bb.putLong(machineid); - } - - public int getSize() { - return Long.BYTES + Byte.BYTES + Integer.BYTES + key.length(); - } - - public byte getType() { - return Entry.TypeNewKey; - } - - public Entry getCopy(Slot s) { - return new NewKey(s, key, machineid); - } -} \ No newline at end of file diff --git a/src2/java/iotcloud/Pair.java b/src2/java/iotcloud/Pair.java deleted file mode 100644 index 73ed6bd..0000000 --- a/src2/java/iotcloud/Pair.java +++ /dev/null @@ -1,23 +0,0 @@ -package iotcloud; - -class Pair { - private A a; - private B b; - - Pair(A a, B b) { - this.a=a; - this.b=b; - } - - A getFirst() { - return a; - } - - B getSecond() { - return b; - } - - public String toString() { - return "<"+a+","+b+">"; - } -} diff --git a/src2/java/iotcloud/PendingTransaction.java b/src2/java/iotcloud/PendingTransaction.java deleted file mode 100644 index c3c41c5..0000000 --- a/src2/java/iotcloud/PendingTransaction.java +++ /dev/null @@ -1,111 +0,0 @@ -package iotcloud; - -import java.util.Set; -import java.util.HashSet; - -import javax.script.ScriptException; -import java.lang.NullPointerException; - - -class PendingTransaction { - - static final byte Equal = Guard.Equal; - static final byte NotEqual = Guard.NotEqual; - - private Set keyValueUpdateSet; - private Guard guard; - private long arbitrator = -1; - - public PendingTransaction() { - keyValueUpdateSet = new HashSet(); - guard = new Guard(); - } - - /** - * Add a new key value to the updates - * - */ - public void addKV(KeyValue newKV) { - - KeyValue rmKV = null; - - // Make sure there are no duplicates - for (KeyValue kv : keyValueUpdateSet) { - if (kv.getKey().equals(newKV.getKey())) { - - // Remove key if we are adding a newer version of the same key - rmKV = kv; - break; - } - } - - // Remove key if we are adding a newer version of the same key - if (rmKV != null) { - keyValueUpdateSet.remove(rmKV); - } - - // Add the key to the hash set - keyValueUpdateSet.add(newKV); - } - - public boolean checkArbitrator(long arb) { - if (arbitrator == -1) { - arbitrator = arb; - return true; - } - - return arb == arbitrator; - } - - - - /** - * Get the key value update set - * - */ - public Set getKVUpdates() { - return keyValueUpdateSet; - } - - /** - * Get the guard - * - */ - public Guard getGuard() { - return guard; - } - - /** - * Add a guard to this transaction - * - */ - public void addGuard(Guard _guard) { - guard = _guard; - } - - /** - * Evaluate the guard expression for a given transaction using a set of key value pairs. - * - */ - public boolean evaluate(Set kvSet) throws ScriptException, NullPointerException { - - // Evaluate the guard using the current KV Set - return guard.evaluate(kvSet); - } - - /** - * Add a boolean expression to the guard. - * - */ - public void setGuardExpression(String expr) { - guard.setGuardExpression(expr); - } - - /** - * Trampoline static method. - * - */ - public static String createExpression(IoTString keyName, IoTString keyValue, byte op) { - return Guard.createExpression(keyName, keyValue, op); - } -} \ No newline at end of file diff --git a/src2/java/iotcloud/RejectedMessage.java b/src2/java/iotcloud/RejectedMessage.java deleted file mode 100644 index 9c84f18..0000000 --- a/src2/java/iotcloud/RejectedMessage.java +++ /dev/null @@ -1,88 +0,0 @@ -package iotcloud; -import java.nio.ByteBuffer; -import java.util.HashSet; - -/** - * Entry for tracking messages that the server rejected. We have to - * make sure that all clients know that this message was rejected to - * prevent the server from reusing these messages in an attack. - * @author Brian Demsky - * @version 1.0 - */ - - -class RejectedMessage extends Entry { - /* Machine identifier */ - private long machineid; - /* Oldest sequence number in range */ - private long oldseqnum; - /* Newest sequence number in range */ - private long newseqnum; - /* Is the machine identifier of the relevant slots equal to (or not - * equal to) the specified machine identifier. */ - private boolean equalto; - /* Set of machines that have not received notification. */ - private HashSet watchset; - - RejectedMessage(Slot slot, long _machineid, long _oldseqnum, long _newseqnum, boolean _equalto) { - super(slot); - machineid=_machineid; - oldseqnum=_oldseqnum; - newseqnum=_newseqnum; - equalto=_equalto; - } - - long getOldSeqNum() { - return oldseqnum; - } - - long getNewSeqNum() { - return newseqnum; - } - - boolean getEqual() { - return equalto; - } - - long getMachineID() { - return machineid; - } - - static Entry decode(Slot slot, ByteBuffer bb) { - long machineid=bb.getLong(); - long oldseqnum=bb.getLong(); - long newseqnum=bb.getLong(); - byte equalto=bb.get(); - return new RejectedMessage(slot, machineid, oldseqnum, newseqnum, equalto==1); - } - - void setWatchSet(HashSet _watchset) { - watchset=_watchset; - } - - void removeWatcher(long machineid) { - if (watchset.remove(machineid)) - if (watchset.isEmpty()) - setDead(); - } - - void encode(ByteBuffer bb) { - bb.put(Entry.TypeRejectedMessage); - bb.putLong(machineid); - bb.putLong(oldseqnum); - bb.putLong(newseqnum); - bb.put(equalto?(byte)1:(byte)0); - } - - int getSize() { - return 3*Long.BYTES + 2*Byte.BYTES; - } - - byte getType() { - return Entry.TypeRejectedMessage; - } - - Entry getCopy(Slot s) { - return new RejectedMessage(s, machineid, oldseqnum, newseqnum, equalto); - } -} diff --git a/src2/java/iotcloud/Slot.java b/src2/java/iotcloud/Slot.java deleted file mode 100644 index 5828fd3..0000000 --- a/src2/java/iotcloud/Slot.java +++ /dev/null @@ -1,214 +0,0 @@ -package iotcloud; -import java.util.Vector; -import java.nio.ByteBuffer; -import javax.crypto.Mac; -import java.util.Arrays; - -/** - * Data structuring for holding Slot information. - * @author Brian Demsky - * @version 1.0 - */ - -class Slot implements Liveness { - /** Sets the slot size. */ - static final int SLOT_SIZE=2048; - /** Sets the size for the HMAC. */ - static final int HMAC_SIZE=32; - - /** Sequence number of the slot. */ - private long seqnum; - /** HMAC of previous slot. */ - private byte[] prevhmac; - /** HMAC of this slot. */ - private byte[] hmac; - /** Machine that sent this slot. */ - private long machineid; - /** Vector of entries in this slot. */ - private Vector entries; - /** Pieces of information that are live. */ - private int livecount; - /** Flag that indicates whether this slot is still live for - * recording the machine that sent it. */ - private boolean seqnumlive; - /** Number of bytes of free space. */ - private int freespace; - /** Reference to Table */ - private Table table; - - Slot(Table _table, long _seqnum, long _machineid, byte[] _prevhmac, byte[] _hmac) { - seqnum=_seqnum; - machineid=_machineid; - prevhmac=_prevhmac; - hmac=_hmac; - entries=new Vector(); - livecount=1; - seqnumlive=true; - freespace = SLOT_SIZE - getBaseSize(); - table=_table; - } - - Slot(Table _table, long _seqnum, long _machineid, byte[] _prevhmac) { - this(_table, _seqnum, _machineid, _prevhmac, null); - } - - Slot(Table _table, long _seqnum, long _machineid) { - this(_table, _seqnum, _machineid, new byte[HMAC_SIZE], null); - } - - byte[] getHMAC() { - return hmac; - } - - byte[] getPrevHMAC() { - return prevhmac; - } - - void addEntry(Entry e) { - e=e.getCopy(this); - entries.add(e); - livecount++; - freespace -= e.getSize(); - } - - private void 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. */ - - boolean hasSpace(Entry e) { - int newfreespace = freespace - e.getSize(); - return newfreespace >= 0; - } - - Vector getEntries() { - return entries; - } - - static Slot decode(Table table, byte[] array, Mac mac) { - mac.update(array, HMAC_SIZE, array.length-HMAC_SIZE); - byte[] realmac=mac.doFinal(); - - ByteBuffer bb=ByteBuffer.wrap(array); - byte[] hmac=new byte[HMAC_SIZE]; - byte[] prevhmac=new byte[HMAC_SIZE]; - bb.get(hmac); - bb.get(prevhmac); - if (!Arrays.equals(realmac, hmac)) - throw new Error("Server Error: Invalid HMAC! Potential Attack!"); - - long seqnum=bb.getLong(); - long machineid=bb.getLong(); - int numentries=bb.getInt(); - Slot slot=new Slot(table, seqnum, machineid, prevhmac, hmac); - - for(int i=0; i getLiveEntries(boolean resize) { - Vector liveEntries=new Vector(); - for(Entry entry: entries) { - if (entry.isLive()) { - if (!resize || entry.getType() != Entry.TypeTableStatus) - liveEntries.add(entry); - } - } - - if (seqnumlive && !resize) - liveEntries.add(new LastMessage(this, machineid, seqnum)); - - return liveEntries; - } - - /** - * Returns the sequence number of the slot. - */ - - long getSequenceNumber() { - return seqnum; - } - - /** - * Returns the machine that sent this slot. - */ - - long getMachineID() { - return machineid; - } - - /** - * Records that a newer slot records the fact that this slot was - * sent by the relevant machine. - */ - - void setDead() { - seqnumlive=false; - decrementLiveCount(); - } - - /** - * Update the count of live entries. - */ - - void decrementLiveCount() { - livecount--; - if (livecount==0) - table.decrementLiveCount(); - } - - /** - * Returns whether the slot stores any live information. - */ - - boolean isLive() { - return livecount > 0; - } - - public String toString() { - return "<"+getSequenceNumber()+">"; - } -} diff --git a/src2/java/iotcloud/SlotBuffer.java b/src2/java/iotcloud/SlotBuffer.java deleted file mode 100644 index 14bc926..0000000 --- a/src2/java/iotcloud/SlotBuffer.java +++ /dev/null @@ -1,99 +0,0 @@ -package iotcloud; - -/** - * Circular buffer that holds the live set of slots. - * @author Brian Demsky - * @version 1.0 - */ - -class SlotBuffer { - static final int DEFAULT_SIZE = 128; - - private Slot[] array; - private int head; - private int tail; - private long oldestseqn; - - SlotBuffer() { - array=new Slot[DEFAULT_SIZE+1]; - head=tail=0; - oldestseqn=0; - } - - int size() { - if (head >= tail) - return head - tail; - return (array.length + head) - tail; - } - - int capacity() { - return array.length - 1; - } - - void resize(int newsize) { - if (newsize == (array.length-1)) - return; - Slot[] newarray = new Slot[newsize+1]; - int currsize = size(); - int index = tail; - for(int i=0; i < currsize; i++) { - newarray[i] = array[index]; - if ((++index) == array.length) - index = 0; - } - array = newarray; - tail = 0; - head = currsize; - } - - private void incrementHead() { - head++; - if (head >= array.length) - head=0; - } - - private void incrementTail() { - tail++; - if (tail >= array.length) - tail=0; - } - - void putSlot(Slot s) { - array[head]=s; - incrementHead(); - - if (oldestseqn==0) - oldestseqn = s.getSequenceNumber(); - - if (head==tail) { - incrementTail(); - oldestseqn++; - } - } - - Slot getSlot(long seqnum) { - int diff=(int) (seqnum-oldestseqn); - int index=diff + tail; - if (index >= array.length) { - if (head >= tail) - return null; - index-= array.length; - } - - if (index >= array.length) - return null; - - if (head >= tail && index >= head) - return null; - - return array[index]; - } - - long getOldestSeqNum() { - return oldestseqn; - } - - long getNewestSeqNum() { - return oldestseqn + size() - 1; - } -} diff --git a/src2/java/iotcloud/SlotIndexer.java b/src2/java/iotcloud/SlotIndexer.java deleted file mode 100644 index cecdf2d..0000000 --- a/src2/java/iotcloud/SlotIndexer.java +++ /dev/null @@ -1,31 +0,0 @@ -package iotcloud; - -/** - * Slot indexer allows slots in both the slot buffer and the new - * server response to looked up in a consistent fashion. - * @author Brian Demsky - * @version 1.0 - */ - -class SlotIndexer { - private Slot[] updates; - private SlotBuffer buffer; - private long firstslotseqnum; - - SlotIndexer(Slot[] _updates, SlotBuffer _buffer) { - buffer = _buffer; - updates = _updates; - firstslotseqnum = updates[0].getSequenceNumber(); - } - - Slot getSlot(long seqnum) { - if (seqnum >= firstslotseqnum) { - int offset = (int) (seqnum - firstslotseqnum); - if (offset >= updates.length) - throw new Error("Invalid Slot Sequence Number Reference"); - else - return updates[offset]; - } else - return buffer.getSlot(seqnum); - } -} diff --git a/src2/java/iotcloud/Table.java b/src2/java/iotcloud/Table.java deleted file mode 100644 index cf21f48..0000000 --- a/src2/java/iotcloud/Table.java +++ /dev/null @@ -1,1120 +0,0 @@ -package iotcloud; -import java.util.HashMap; -import java.util.Map; -import java.util.Iterator; -import java.util.HashSet; -import java.util.Arrays; -import java.util.Vector; -import java.util.Random; -import java.util.Queue; -import java.util.LinkedList; -import java.util.List; -import java.util.Set; -import java.util.Collection; - -/** - * IoTTable data structure. Provides client inferface. - * @author Brian Demsky - * @version 1.0 - */ - -final public class Table { - private int numslots; //number of slots stored in buffer - - //table of key-value pairs - //private HashMap table = new HashMap(); - - // machine id -> (sequence number, Slot or LastMessage); records last message by each client - private HashMap > lastmessagetable = new HashMap >(); - // machine id -> ... - private HashMap > watchlist = new HashMap >(); - private Vector rejectedmessagelist = new Vector(); - private SlotBuffer buffer; - private CloudComm cloud; - private long sequencenumber; //Largest sequence number a client has received - private long localmachineid; - private TableStatus lastTableStatus; - static final int FREE_SLOTS = 10; //number of slots that should be kept free - static final int SKIP_THRESHOLD = 10; - private long liveslotcount = 0; - private int chance; - static final double RESIZE_MULTIPLE = 1.2; - static final double RESIZE_THRESHOLD = 0.75; - static final int REJECTED_THRESHOLD = 5; - private int resizethreshold; - private long lastliveslotseqn; //smallest sequence number with a live entry - private Random random = new Random(); - - private PendingTransaction pendingTransBuild = null; // Pending Transaction used in building - private Queue pendingTransQueue = null; // Queue of pending transactions - private List commitList = null; // List of all the most recent live commits - private Set abortSet = null; // Set of the live aborts - private Map commitedTable = null; // Table of committed KV - private Map speculativeTable = null; // Table of speculative KV - private List uncommittedTransactionsList = null; // - private Map arbitratorTable = null; // Table of arbitrators - // private Set arbitratorTable = null; // Table of arbitrators - - - public Table(String baseurl, String password, long _localmachineid) { - localmachineid = _localmachineid; - buffer = new SlotBuffer(); - numslots = buffer.capacity(); - setResizeThreshold(); - sequencenumber = 0; - cloud = new CloudComm(this, baseurl, password); - lastliveslotseqn = 1; - - pendingTransQueue = new LinkedList(); - commitList = new LinkedList(); - abortSet = new HashSet(); - commitedTable = new HashMap(); - speculativeTable = new HashMap(); - uncommittedTransactionsList = new LinkedList(); - arbitratorTable = new HashMap(); - } - - public Table(CloudComm _cloud, long _localmachineid) { - localmachineid = _localmachineid; - buffer = new SlotBuffer(); - numslots = buffer.capacity(); - setResizeThreshold(); - sequencenumber = 0; - cloud = _cloud; - - pendingTransQueue = new LinkedList(); - commitList = new LinkedList(); - abortSet = new HashSet(); - commitedTable = new HashMap(); - speculativeTable = new HashMap(); - uncommittedTransactionsList = new LinkedList(); - arbitratorTable = new HashMap(); - } - - public void rebuild() { - Slot[] newslots = cloud.getSlots(sequencenumber + 1); - validateandupdate(newslots, true); - } - - - - public IoTString getCommitted(IoTString key) { - KeyValue kv = commitedTable.get(key); - if (kv != null) { - return kv.getValue(); - } else { - return null; - } - } - - public IoTString getSpeculative(IoTString key) { - KeyValue kv = speculativeTable.get(key); - if (kv != null) { - return kv.getValue(); - } else { - return null; - } - } - - - public void initTable() { - cloud.setSalt();//Set the salt - Slot s = new Slot(this, 1, localmachineid); - TableStatus status = new TableStatus(s, numslots); - s.addEntry(status); - Slot[] array = cloud.putSlot(s, numslots); - if (array == null) { - array = new Slot[] {s}; - /* update data structure */ - validateandupdate(array, true); - } else { - throw new Error("Error on initialization"); - } - } - - public String toString() { - - - String retString = " Committed Table: \n"; - retString += "---------------------------\n"; - retString += commitedTable.toString(); - - retString += "\n\n"; - - retString += " Speculative Table: \n"; - retString += "---------------------------\n"; - retString += speculativeTable.toString(); - - return retString; - } - - - - - - - public void startTransaction() { - // Create a new transaction, invalidates any old pending transactions. - pendingTransBuild = new PendingTransaction(); - } - - public void commitTransaction() { - - if (pendingTransBuild.getKVUpdates().size() == 0) { - // If no updates are made then there is no point inserting into the chain - return; - } - - // Add the pending transaction to the queue - pendingTransQueue.add(pendingTransBuild); - - while (!pendingTransQueue.isEmpty()) { - if (tryput( pendingTransQueue.peek(), false)) { - pendingTransQueue.poll(); - } - } - } - - public void addKV(IoTString key, IoTString value) { - - // Make sure new key value pair matches the current arbitrator - if (!pendingTransBuild.checkArbitrator(arbitratorTable.get(key))) { - // TODO: Maybe not throw and error - throw new Error("Not all Key Values match"); - } - - - - KeyValue kv = new KeyValue(key, value); - pendingTransBuild.addKV(kv); - } - - public void addGuard(Guard guard) { - pendingTransBuild.addGuard(guard); - } - - public void update() { - Slot[] newslots = cloud.getSlots(sequencenumber + 1); - - validateandupdate(newslots, false); - - if (uncommittedTransactionsList.size() > 0) { - List uncommittedTransArb = new LinkedList(); - - for (Transaction ut : uncommittedTransactionsList) { - KeyValue kv = (KeyValue)(ut.getkeyValueUpdateSet().toArray()[0]); - long arb = arbitratorTable.get(kv.getKey()); - - if (arb == localmachineid) { - uncommittedTransArb.add(ut); - } - } - - - boolean needResize = false; - while (uncommittedTransArb.size() > 0) { - boolean resize = needResize; - needResize = false; - - Slot s = new Slot(this, sequencenumber + 1, localmachineid, buffer.getSlot(sequencenumber).getHMAC()); - int newsize = 0; - if (liveslotcount > resizethreshold) { - resize = true; //Resize is forced - } - - if (resize) { - newsize = (int) (numslots * RESIZE_MULTIPLE); - TableStatus status = new TableStatus(s, newsize); - s.addEntry(status); - } - - if (! rejectedmessagelist.isEmpty()) { - /* TODO: We should avoid generating a rejected message entry if - * there is already a sufficient entry in the queue (e.g., - * equalsto value of true and same sequence number). */ - - long old_seqn = rejectedmessagelist.firstElement(); - if (rejectedmessagelist.size() > REJECTED_THRESHOLD) { - long new_seqn = rejectedmessagelist.lastElement(); - RejectedMessage rm = new RejectedMessage(s, localmachineid, old_seqn, new_seqn, false); - s.addEntry(rm); - } else { - long prev_seqn = -1; - int i = 0; - /* Go through list of missing messages */ - for (; i < rejectedmessagelist.size(); i++) { - long curr_seqn = rejectedmessagelist.get(i); - Slot s_msg = buffer.getSlot(curr_seqn); - if (s_msg != null) - break; - prev_seqn = curr_seqn; - } - /* Generate rejected message entry for missing messages */ - if (prev_seqn != -1) { - RejectedMessage rm = new RejectedMessage(s, localmachineid, old_seqn, prev_seqn, false); - s.addEntry(rm); - } - /* Generate rejected message entries for present messages */ - for (; i < rejectedmessagelist.size(); i++) { - long curr_seqn = rejectedmessagelist.get(i); - Slot s_msg = buffer.getSlot(curr_seqn); - long machineid = s_msg.getMachineID(); - RejectedMessage rm = new RejectedMessage(s, machineid, curr_seqn, curr_seqn, true); - s.addEntry(rm); - } - } - } - - long newestseqnum = buffer.getNewestSeqNum(); - long oldestseqnum = buffer.getOldestSeqNum(); - if (lastliveslotseqn < oldestseqnum) { - lastliveslotseqn = oldestseqnum; - } - - long seqn = lastliveslotseqn; - boolean seenliveslot = false; - long firstiffull = newestseqnum + 1 - numslots; //smallest seq number in the buffer if it is full - long threshold = firstiffull + FREE_SLOTS; //we want the buffer to be clear of live entries up to this point - - boolean tryAgain = false; - - // Mandatory Rescue - for (; seqn < threshold; seqn++) { - Slot prevslot = buffer.getSlot(seqn); - //Push slot number forward - if (! seenliveslot) - lastliveslotseqn = seqn; - - if (! prevslot.isLive()) - continue; - seenliveslot = true; - Vector liveentries = prevslot.getLiveEntries(resize); - for (Entry liveentry : liveentries) { - if (s.hasSpace(liveentry)) { - s.addEntry(liveentry); - } else if (seqn == firstiffull) { //if there's no space but the entry is about to fall off the queue - if (!resize) { - System.out.print("B"); //? - tryAgain = true; - needResize = true; - } - } - } - } - - if (tryAgain) { - continue; - } - - // Arbitrate - Map speculativeTableTmp = new HashMap(commitedTable); - for (Iterator i = uncommittedTransArb.iterator(); i.hasNext();) { - Transaction ut = i.next(); - - KeyValue keyVal = (KeyValue)(ut.getkeyValueUpdateSet().toArray())[0]; - // Check if this machine arbitrates for this transaction - if (arbitratorTable.get( keyVal.getKey() ) != localmachineid ) { - continue; - } - - Entry newEntry = null; - - try { - if ( ut.getGuard().evaluate(new HashSet(speculativeTableTmp.values()))) { - // Guard evaluated as true - - // update the local tmp current key set - for (KeyValue kv : ut.getkeyValueUpdateSet()) { - speculativeTableTmp.put(kv.getKey(), kv); - } - - // create the commit - newEntry = new Commit(s, ut.getSequenceNumber(), ut.getkeyValueUpdateSet()); - } else { - // Guard was false - - // create the abort - newEntry = new Abort(s, ut.getSequenceNumber(), ut.getMachineID()); - } - } catch (Exception e) { - e.printStackTrace(); - } - - if ((newEntry != null) && s.hasSpace(newEntry)) { - s.addEntry(newEntry); - i.remove(); - - } else { - break; - } - } - - /* now go through live entries from least to greatest sequence number until - * either all live slots added, or the slot doesn't have enough room - * for SKIP_THRESHOLD consecutive entries*/ - int skipcount = 0; - search: - for (; seqn <= newestseqnum; seqn++) { - Slot prevslot = buffer.getSlot(seqn); - //Push slot number forward - if (!seenliveslot) - lastliveslotseqn = seqn; - - if (!prevslot.isLive()) - continue; - seenliveslot = true; - Vector liveentries = prevslot.getLiveEntries(resize); - for (Entry liveentry : liveentries) { - if (s.hasSpace(liveentry)) - s.addEntry(liveentry); - else { - skipcount++; - if (skipcount > SKIP_THRESHOLD) - break search; - } - } - } - - int max = 0; - if (resize) - max = newsize; - Slot[] array = cloud.putSlot(s, max); - if (array == null) { - array = new Slot[] {s}; - rejectedmessagelist.clear(); - } else { - if (array.length == 0) - throw new Error("Server Error: Did not send any slots"); - rejectedmessagelist.add(s.getSequenceNumber()); - } - - /* update data structure */ - validateandupdate(array, true); - } - - - } - } - - public boolean createNewKey(IoTString keyName, long machineId) { - - while (true) { - if (arbitratorTable.get(keyName) != null) { - // There is already an arbitrator - return false; - } - - if (tryput(keyName, machineId, false)) { - - // If successfully inserted - return true; - } - } - } - - void decrementLiveCount() { - liveslotcount--; - } - - - private void setResizeThreshold() { - int resize_lower = (int) (RESIZE_THRESHOLD * numslots); - resizethreshold = resize_lower - 1 + random.nextInt(numslots - resize_lower); - } - - private boolean tryput(PendingTransaction pendingTrans, boolean resize) { - Slot s = new Slot(this, sequencenumber + 1, localmachineid, buffer.getSlot(sequencenumber).getHMAC()); - int newsize = 0; - if (liveslotcount > resizethreshold) { - resize = true; //Resize is forced - } - - if (resize) { - newsize = (int) (numslots * RESIZE_MULTIPLE); - TableStatus status = new TableStatus(s, newsize); - s.addEntry(status); - } - - if (! rejectedmessagelist.isEmpty()) { - /* TODO: We should avoid generating a rejected message entry if - * there is already a sufficient entry in the queue (e.g., - * equalsto value of true and same sequence number). */ - - long old_seqn = rejectedmessagelist.firstElement(); - if (rejectedmessagelist.size() > REJECTED_THRESHOLD) { - long new_seqn = rejectedmessagelist.lastElement(); - RejectedMessage rm = new RejectedMessage(s, localmachineid, old_seqn, new_seqn, false); - s.addEntry(rm); - } else { - long prev_seqn = -1; - int i = 0; - /* Go through list of missing messages */ - for (; i < rejectedmessagelist.size(); i++) { - long curr_seqn = rejectedmessagelist.get(i); - Slot s_msg = buffer.getSlot(curr_seqn); - if (s_msg != null) - break; - prev_seqn = curr_seqn; - } - /* Generate rejected message entry for missing messages */ - if (prev_seqn != -1) { - RejectedMessage rm = new RejectedMessage(s, localmachineid, old_seqn, prev_seqn, false); - s.addEntry(rm); - } - /* Generate rejected message entries for present messages */ - for (; i < rejectedmessagelist.size(); i++) { - long curr_seqn = rejectedmessagelist.get(i); - Slot s_msg = buffer.getSlot(curr_seqn); - long machineid = s_msg.getMachineID(); - RejectedMessage rm = new RejectedMessage(s, machineid, curr_seqn, curr_seqn, true); - s.addEntry(rm); - } - } - } - - long newestseqnum = buffer.getNewestSeqNum(); - long oldestseqnum = buffer.getOldestSeqNum(); - if (lastliveslotseqn < oldestseqnum) - lastliveslotseqn = oldestseqnum; - - long seqn = lastliveslotseqn; - boolean seenliveslot = false; - long firstiffull = newestseqnum + 1 - numslots; //smallest seq number in the buffer if it is full - long threshold = firstiffull + FREE_SLOTS; //we want the buffer to be clear of live entries up to this point - - - // Mandatory Rescue - for (; seqn < threshold; seqn++) { - Slot prevslot = buffer.getSlot(seqn); - //Push slot number forward - if (! seenliveslot) - lastliveslotseqn = seqn; - - if (! prevslot.isLive()) - continue; - seenliveslot = true; - Vector liveentries = prevslot.getLiveEntries(resize); - for (Entry liveentry : liveentries) { - if (s.hasSpace(liveentry)) { - s.addEntry(liveentry); - } else if (seqn == firstiffull) { //if there's no space but the entry is about to fall off the queue - if (!resize) { - System.out.print("B"); //? - return tryput(pendingTrans, true); - } - } - } - } - - - // Arbitrate - Map speculativeTableTmp = new HashMap(commitedTable); - for (Transaction ut : uncommittedTransactionsList) { - - KeyValue keyVal = (KeyValue)(ut.getkeyValueUpdateSet().toArray())[0]; - // Check if this machine arbitrates for this transaction - if (arbitratorTable.get( keyVal.getKey() ) != localmachineid ) { - continue; - } - - Entry newEntry = null; - - try { - if ( ut.getGuard().evaluate(new HashSet(speculativeTableTmp.values()))) { - // Guard evaluated as true - - // update the local tmp current key set - for (KeyValue kv : ut.getkeyValueUpdateSet()) { - speculativeTableTmp.put(kv.getKey(), kv); - } - - // create the commit - newEntry = new Commit(s, ut.getSequenceNumber(), ut.getkeyValueUpdateSet()); - } else { - // Guard was false - - // create the abort - newEntry = new Abort(s, ut.getSequenceNumber(), ut.getMachineID()); - } - } catch (Exception e) { - e.printStackTrace(); - } - - if ((newEntry != null) && s.hasSpace(newEntry)) { - s.addEntry(newEntry); - } else { - break; - } - } - - Transaction trans = new Transaction(s, - s.getSequenceNumber(), - localmachineid, - pendingTrans.getKVUpdates(), - pendingTrans.getGuard()); - boolean insertedTrans = false; - if (s.hasSpace(trans)) { - s.addEntry(trans); - insertedTrans = true; - } - - /* now go through live entries from least to greatest sequence number until - * either all live slots added, or the slot doesn't have enough room - * for SKIP_THRESHOLD consecutive entries*/ - int skipcount = 0; - search: - for (; seqn <= newestseqnum; seqn++) { - Slot prevslot = buffer.getSlot(seqn); - //Push slot number forward - if (!seenliveslot) - lastliveslotseqn = seqn; - - if (!prevslot.isLive()) - continue; - seenliveslot = true; - Vector liveentries = prevslot.getLiveEntries(resize); - for (Entry liveentry : liveentries) { - if (s.hasSpace(liveentry)) - s.addEntry(liveentry); - else { - skipcount++; - if (skipcount > SKIP_THRESHOLD) - break search; - } - } - } - - int max = 0; - if (resize) - max = newsize; - Slot[] array = cloud.putSlot(s, max); - if (array == null) { - array = new Slot[] {s}; - rejectedmessagelist.clear(); - } else { - if (array.length == 0) - throw new Error("Server Error: Did not send any slots"); - rejectedmessagelist.add(s.getSequenceNumber()); - insertedTrans = false; - } - - /* update data structure */ - validateandupdate(array, true); - - return insertedTrans; - } - - private boolean tryput(IoTString keyName, long arbMachineid, boolean resize) { - Slot s = new Slot(this, sequencenumber + 1, localmachineid, buffer.getSlot(sequencenumber).getHMAC()); - int newsize = 0; - if (liveslotcount > resizethreshold) { - resize = true; //Resize is forced - } - - if (resize) { - newsize = (int) (numslots * RESIZE_MULTIPLE); - TableStatus status = new TableStatus(s, newsize); - s.addEntry(status); - } - - if (! rejectedmessagelist.isEmpty()) { - /* TODO: We should avoid generating a rejected message entry if - * there is already a sufficient entry in the queue (e.g., - * equalsto value of true and same sequence number). */ - - long old_seqn = rejectedmessagelist.firstElement(); - if (rejectedmessagelist.size() > REJECTED_THRESHOLD) { - long new_seqn = rejectedmessagelist.lastElement(); - RejectedMessage rm = new RejectedMessage(s, localmachineid, old_seqn, new_seqn, false); - s.addEntry(rm); - } else { - long prev_seqn = -1; - int i = 0; - /* Go through list of missing messages */ - for (; i < rejectedmessagelist.size(); i++) { - long curr_seqn = rejectedmessagelist.get(i); - Slot s_msg = buffer.getSlot(curr_seqn); - if (s_msg != null) - break; - prev_seqn = curr_seqn; - } - /* Generate rejected message entry for missing messages */ - if (prev_seqn != -1) { - RejectedMessage rm = new RejectedMessage(s, localmachineid, old_seqn, prev_seqn, false); - s.addEntry(rm); - } - /* Generate rejected message entries for present messages */ - for (; i < rejectedmessagelist.size(); i++) { - long curr_seqn = rejectedmessagelist.get(i); - Slot s_msg = buffer.getSlot(curr_seqn); - long machineid = s_msg.getMachineID(); - RejectedMessage rm = new RejectedMessage(s, machineid, curr_seqn, curr_seqn, true); - s.addEntry(rm); - } - } - } - - long newestseqnum = buffer.getNewestSeqNum(); - long oldestseqnum = buffer.getOldestSeqNum(); - if (lastliveslotseqn < oldestseqnum) - lastliveslotseqn = oldestseqnum; - - long seqn = lastliveslotseqn; - boolean seenliveslot = false; - long firstiffull = newestseqnum + 1 - numslots; //smallest seq number in the buffer if it is full - long threshold = firstiffull + FREE_SLOTS; //we want the buffer to be clear of live entries up to this point - - - // Mandatory Rescue - for (; seqn < threshold; seqn++) { - Slot prevslot = buffer.getSlot(seqn); - //Push slot number forward - if (! seenliveslot) - lastliveslotseqn = seqn; - - if (! prevslot.isLive()) - continue; - seenliveslot = true; - Vector liveentries = prevslot.getLiveEntries(resize); - for (Entry liveentry : liveentries) { - if (s.hasSpace(liveentry)) { - s.addEntry(liveentry); - } else if (seqn == firstiffull) { //if there's no space but the entry is about to fall off the queue - if (!resize) { - System.out.print("B"); //? - return tryput(keyName, arbMachineid, true); - } - } - } - } - - - // // Arbitrate - // Map speculativeTableTmp = new HashMap(commitedTable); - // for (Transaction ut : uncommittedTransactionsList) { - - // KeyValue keyVal = (KeyValue)(ut.getkeyValueUpdateSet().toArray())[0]; - // // Check if this machine arbitrates for this transaction - // if (arbitratorTable.get( keyVal.getKey() ) != localmachineid ) { - // continue; - // } - - // Entry newEntry = null; - - // try { - // if ( ut.getGuard().evaluate(new HashSet(speculativeTableTmp.values()))) { - // // Guard evaluated as true - - // // update the local tmp current key set - // for (KeyValue kv : ut.getkeyValueUpdateSet()) { - // speculativeTableTmp.put(kv.getKey(), kv); - // } - - // // create the commit - // newEntry = new Commit(s, ut.getSequenceNumber(), ut.getkeyValueUpdateSet()); - // } else { - // // Guard was false - - // // create the abort - // newEntry = new Abort(s, ut.getSequenceNumber(), ut.getMachineID()); - // } - // } catch (Exception e) { - // e.printStackTrace(); - // } - - // if ((newEntry != null) && s.hasSpace(newEntry)) { - - // // TODO: Remove print - // System.out.println("Arbitrating..."); - // s.addEntry(newEntry); - // } else { - // break; - // } - // } - - - NewKey newKey = new NewKey(s, keyName, arbMachineid); - - boolean insertedNewKey = false; - if (s.hasSpace(newKey)) { - s.addEntry(newKey); - insertedNewKey = true; - } - - /* now go through live entries from least to greatest sequence number until - * either all live slots added, or the slot doesn't have enough room - * for SKIP_THRESHOLD consecutive entries*/ - int skipcount = 0; - search: - for (; seqn <= newestseqnum; seqn++) { - Slot prevslot = buffer.getSlot(seqn); - //Push slot number forward - if (!seenliveslot) - lastliveslotseqn = seqn; - - if (!prevslot.isLive()) - continue; - seenliveslot = true; - Vector liveentries = prevslot.getLiveEntries(resize); - for (Entry liveentry : liveentries) { - if (s.hasSpace(liveentry)) - s.addEntry(liveentry); - else { - skipcount++; - if (skipcount > SKIP_THRESHOLD) - break search; - } - } - } - - int max = 0; - if (resize) - max = newsize; - Slot[] array = cloud.putSlot(s, max); - if (array == null) { - array = new Slot[] {s}; - rejectedmessagelist.clear(); - } else { - if (array.length == 0) - throw new Error("Server Error: Did not send any slots"); - rejectedmessagelist.add(s.getSequenceNumber()); - insertedNewKey = false; - } - - /* update data structure */ - validateandupdate(array, true); - - return insertedNewKey; - } - - private void validateandupdate(Slot[] newslots, boolean acceptupdatestolocal) { - /* The cloud communication layer has checked slot HMACs already - before decoding */ - if (newslots.length == 0) return; - - long firstseqnum = newslots[0].getSequenceNumber(); - if (firstseqnum <= sequencenumber) { - throw new Error("Server Error: Sent older slots!"); - } - - SlotIndexer indexer = new SlotIndexer(newslots, buffer); - checkHMACChain(indexer, newslots); - - HashSet machineSet = new HashSet(lastmessagetable.keySet()); // - - initExpectedSize(firstseqnum); - for (Slot slot : newslots) { - processSlot(indexer, slot, acceptupdatestolocal, machineSet); - updateExpectedSize(); - } - - /* If there is a gap, check to see if the server sent us everything. */ - if (firstseqnum != (sequencenumber + 1)) { - - // TODO: Check size - checkNumSlots(newslots.length); - if (!machineSet.isEmpty()) { - throw new Error("Missing record for machines: " + machineSet); - } - } - - commitNewMaxSize(); - - /* Commit new to slots. */ - for (Slot slot : newslots) { - buffer.putSlot(slot); - liveslotcount++; - } - sequencenumber = newslots[newslots.length - 1].getSequenceNumber(); - - // Speculate on key value pairs - createSpeculativeTable(); - } - - private void createSpeculativeTable() { - Map speculativeTableTmp = new HashMap(commitedTable); - - for (Transaction trans : uncommittedTransactionsList) { - - try { - if (trans.getGuard().evaluate(new HashSet(speculativeTableTmp.values()))) { - for (KeyValue kv : trans.getkeyValueUpdateSet()) { - speculativeTableTmp.put(kv.getKey(), kv); - } - } - - } catch (Exception e) { - e.printStackTrace(); - } - } - - speculativeTable = speculativeTableTmp; - } - - private int expectedsize, currmaxsize; - - private void checkNumSlots(int numslots) { - if (numslots != expectedsize) { - throw new Error("Server Error: Server did not send all slots. Expected: " + expectedsize + " Received:" + numslots); - } - } - - private void initExpectedSize(long firstsequencenumber) { - long prevslots = firstsequencenumber; - expectedsize = (prevslots < ((long) numslots)) ? (int) prevslots : numslots; - currmaxsize = numslots; - } - - private void updateExpectedSize() { - expectedsize++; - if (expectedsize > currmaxsize) { - expectedsize = currmaxsize; - } - } - - private void updateCurrMaxSize(int newmaxsize) { - currmaxsize = newmaxsize; - } - - private void commitNewMaxSize() { - if (numslots != currmaxsize) - buffer.resize(currmaxsize); - - numslots = currmaxsize; - setResizeThreshold(); - } - - - - - - private void processEntry(LastMessage entry, HashSet machineSet) { - updateLastMessage(entry.getMachineID(), entry.getSequenceNumber(), entry, false, machineSet); - } - - private void processEntry(RejectedMessage entry, SlotIndexer indexer) { - long oldseqnum = entry.getOldSeqNum(); - long newseqnum = entry.getNewSeqNum(); - boolean isequal = entry.getEqual(); - long machineid = entry.getMachineID(); - for (long seqnum = oldseqnum; seqnum <= newseqnum; seqnum++) { - Slot slot = indexer.getSlot(seqnum); - if (slot != null) { - long slotmachineid = slot.getMachineID(); - if (isequal != (slotmachineid == machineid)) { - throw new Error("Server Error: Trying to insert rejected message for slot " + seqnum); - } - } - } - - HashSet watchset = new HashSet(); - for (Map.Entry > lastmsg_entry : lastmessagetable.entrySet()) { - long entry_mid = lastmsg_entry.getKey(); - /* We've seen it, don't need to continue to watch. Our next - * message will implicitly acknowledge it. */ - if (entry_mid == localmachineid) - continue; - Pair v = lastmsg_entry.getValue(); - long entry_seqn = v.getFirst(); - if (entry_seqn < newseqnum) { - addWatchList(entry_mid, entry); - watchset.add(entry_mid); - } - } - if (watchset.isEmpty()) - entry.setDead(); - else - entry.setWatchSet(watchset); - } - - private void processEntry(NewKey entry) { - arbitratorTable.put(entry.getKey(), entry.getMachineID()); - } - - private void processEntry(Transaction entry) { - uncommittedTransactionsList.add(entry); - } - - private void processEntry(Abort entry) { - - - if (lastmessagetable.get(entry.getMachineID()).getFirst() < entry.getTransSequenceNumber()) { - // Abort has not been seen yet so we need to keep track of it - abortSet.add(entry); - } else { - // The machine already saw this so it is dead - entry.setDead(); - } - - for (Iterator i = uncommittedTransactionsList.iterator(); i.hasNext();) { - Transaction prevtrans = i.next(); - if (prevtrans.getSequenceNumber() == entry.getTransSequenceNumber()) { - uncommittedTransactionsList.remove(prevtrans); - prevtrans.setDead(); - return; - } - } - } - - private void processEntry(Commit entry) { - - for (Iterator i = commitList.iterator(); i.hasNext();) { - Commit prevcommit = i.next(); - prevcommit.updateLiveKeys(entry.getkeyValueUpdateSet()); - - if (!prevcommit.isLive()) { - //commitList.remove(prevcommit); - i.remove(); - } - } - - commitList.add(entry); - - // Update the committed table list - for (KeyValue kv : entry.getkeyValueUpdateSet()) { - IoTString key = kv.getKey(); - commitedTable.put(key, kv); - } - - long committedTransSeq = entry.getTransSequenceNumber(); - - // Make dead the transactions - for (Iterator i = uncommittedTransactionsList.iterator(); i.hasNext();) { - Transaction prevtrans = i.next(); - - if (prevtrans.getSequenceNumber() <= committedTransSeq) { - // uncommittedTransactionsList.remove(prevtrans); - i.remove(); - prevtrans.setDead(); - } - } - } - - private void processEntry(TableStatus entry) { - int newnumslots = entry.getMaxSlots(); - updateCurrMaxSize(newnumslots); - if (lastTableStatus != null) - lastTableStatus.setDead(); - lastTableStatus = entry; - } - - - private void addWatchList(long machineid, RejectedMessage entry) { - HashSet entries = watchlist.get(machineid); - if (entries == null) - watchlist.put(machineid, entries = new HashSet()); - entries.add(entry); - } - - private void updateLastMessage(long machineid, long seqnum, Liveness liveness, boolean acceptupdatestolocal, HashSet machineSet) { - machineSet.remove(machineid); - - HashSet watchset = watchlist.get(machineid); - if (watchset != null) { - for (Iterator rmit = watchset.iterator(); rmit.hasNext(); ) { - RejectedMessage rm = rmit.next(); - if (rm.getNewSeqNum() <= seqnum) { - /* Remove it from our watchlist */ - rmit.remove(); - /* Decrement machines that need to see this notification */ - rm.removeWatcher(machineid); - } - } - } - - if (machineid == localmachineid) { - /* Our own messages are immediately dead. */ - if (liveness instanceof LastMessage) { - ((LastMessage)liveness).setDead(); - } else if (liveness instanceof Slot) { - ((Slot)liveness).setDead(); - } else { - throw new Error("Unrecognized type"); - } - } - - // Set dead the abort - for (Iterator ait = abortSet.iterator(); ait.hasNext(); ) { - Abort abort = ait.next(); - - if ((abort.getMachineID() == machineid) && (abort.getTransSequenceNumber() <= seqnum)) { - abort.setDead(); - ait.remove(); - } - } - - - Pair lastmsgentry = lastmessagetable.put(machineid, new Pair(seqnum, liveness)); - if (lastmsgentry == null) - return; - - long lastmsgseqnum = lastmsgentry.getFirst(); - Liveness lastentry = lastmsgentry.getSecond(); - if (machineid != localmachineid) { - if (lastentry instanceof LastMessage) { - ((LastMessage)lastentry).setDead(); - } else if (lastentry instanceof Slot) { - ((Slot)lastentry).setDead(); - } else { - throw new Error("Unrecognized type"); - } - } - - if (machineid == localmachineid) { - if (lastmsgseqnum != seqnum && !acceptupdatestolocal) - throw new Error("Server Error: Mismatch on local machine sequence number"); - } else { - if (lastmsgseqnum > seqnum) - throw new Error("Server Error: Rollback on remote machine sequence number"); - } - } - - private void processSlot(SlotIndexer indexer, Slot slot, boolean acceptupdatestolocal, HashSet machineSet) { - updateLastMessage(slot.getMachineID(), slot.getSequenceNumber(), slot, acceptupdatestolocal, machineSet); - for (Entry entry : slot.getEntries()) { - switch (entry.getType()) { - - case Entry.TypeNewKey: - processEntry((NewKey)entry); - break; - - case Entry.TypeCommit: - processEntry((Commit)entry); - break; - - case Entry.TypeAbort: - processEntry((Abort)entry); - break; - - case Entry.TypeTransaction: - processEntry((Transaction)entry); - break; - - case Entry.TypeLastMessage: - processEntry((LastMessage)entry, machineSet); - break; - - case Entry.TypeRejectedMessage: - processEntry((RejectedMessage)entry, indexer); - break; - - case Entry.TypeTableStatus: - processEntry((TableStatus)entry); - break; - - default: - throw new Error("Unrecognized type: " + entry.getType()); - } - } - } - - private void checkHMACChain(SlotIndexer indexer, Slot[] newslots) { - for (int i = 0; i < newslots.length; i++) { - Slot currslot = newslots[i]; - Slot prevslot = indexer.getSlot(currslot.getSequenceNumber() - 1); - if (prevslot != null && - !Arrays.equals(prevslot.getHMAC(), currslot.getPrevHMAC())) - throw new Error("Server Error: Invalid HMAC Chain" + currslot + " " + prevslot); - } - } -} diff --git a/src2/java/iotcloud/TableStatus.java b/src2/java/iotcloud/TableStatus.java deleted file mode 100644 index 62f3a6d..0000000 --- a/src2/java/iotcloud/TableStatus.java +++ /dev/null @@ -1,45 +0,0 @@ -package iotcloud; -import java.nio.ByteBuffer; - -/** - * TableStatus entries record the current size of the data structure - * in slots. Used to remember the size and to perform resizes. - * @author Brian Demsky - * @version 1.0 - */ - - -class TableStatus extends Entry { - private int maxslots; - - TableStatus(Slot slot, int _maxslots) { - super(slot); - maxslots=_maxslots; - } - - int getMaxSlots() { - return maxslots; - } - - static Entry decode(Slot slot, ByteBuffer bb) { - int maxslots=bb.getInt(); - return new TableStatus(slot, maxslots); - } - - void encode(ByteBuffer bb) { - bb.put(Entry.TypeTableStatus); - bb.putInt(maxslots); - } - - int getSize() { - return Integer.BYTES+Byte.BYTES; - } - - byte getType() { - return Entry.TypeTableStatus; - } - - Entry getCopy(Slot s) { - return new TableStatus(s, maxslots); - } -} diff --git a/src2/java/iotcloud/Test.java b/src2/java/iotcloud/Test.java deleted file mode 100644 index 00d4c7c..0000000 --- a/src2/java/iotcloud/Test.java +++ /dev/null @@ -1,75 +0,0 @@ -package iotcloud; - -/** - * Test cases. - * @author Brian Demsky - * @version 1.0 - */ - -public class Test { - public static void main(String[] args) { - if (args[0].equals("2")) { - test2(); - } - } - - static void test2() { - Table t1 = new Table("http://127.0.0.1/test.iotcloud/", "reallysecret", 321); - t1.initTable(); - Table t2 = new Table("http://127.0.0.1/test.iotcloud/", "reallysecret", 351); - t2.update(); - - - - final int NUMBER_OF_TESTS = 200; - - for (int i = 0; i < NUMBER_OF_TESTS; i++) { - - System.out.println("Doing: " + i); - - String a = "a" + i; - String b = "b" + i; - IoTString ia = new IoTString(a); - IoTString ib = new IoTString(b); - - - t1.createNewKey(ia, 351); - t2.createNewKey(ib, 321); - - t1.startTransaction(); - t1.addKV(ia, ia); - t1.commitTransaction(); - } - - for (int i = 0; i < NUMBER_OF_TESTS; i++) { - - System.out.println("Doing: " + i); - - String a = "a" + i; - String b = "b" + i; - IoTString ia = new IoTString(a); - IoTString ib = new IoTString(b); - - t2.startTransaction(); - t2.addKV(ib, ib); - t2.commitTransaction(); - } - - - - t1.update(); - // t2.update(); - // t1.update(); - - for (int i = 0; i < NUMBER_OF_TESTS; i++) { - String a = "a" + i; - String b = "b" + i; - IoTString ia = new IoTString(a); - IoTString ib = new IoTString(b); - - System.out.println(ib + " -> " + t1.getCommitted(ib)); - System.out.println(ia + " -> " + t2.getCommitted(ia)); - System.out.println(); - } - } -} diff --git a/src2/java/iotcloud/Transaction.java b/src2/java/iotcloud/Transaction.java deleted file mode 100644 index 5acd5c2..0000000 --- a/src2/java/iotcloud/Transaction.java +++ /dev/null @@ -1,97 +0,0 @@ -package iotcloud; - -import java.nio.ByteBuffer; -import java.util.Set; -import java.util.HashSet; - -class Transaction extends Entry { - - private long seqnum; - private long machineid; - private Set keyValueUpdateSet = null; - private Guard guard; - - public Transaction(Slot slot, long _seqnum, long _machineid, Set _keyValueUpdateSet, Guard _guard) { - super(slot); - seqnum = _seqnum; - machineid = _machineid; - - keyValueUpdateSet = new HashSet(); - - for (KeyValue kv : _keyValueUpdateSet) { - KeyValue kvCopy = kv.getCopy(); - keyValueUpdateSet.add(kvCopy); - } - - guard = _guard.getCopy(); - } - - public long getMachineID() { - return machineid; - } - - public long getSequenceNumber() { - return seqnum; - } - - public Set getkeyValueUpdateSet() { - return keyValueUpdateSet; - } - - public Guard getGuard() { - return guard; - } - - public byte getType() { - return Entry.TypeTransaction; - } - - public int getSize() { - int size = 2 * Long.BYTES + Byte.BYTES; // seq, machine id, entry type - size += Integer.BYTES; // number of KV's - - // Size of each KV - for (KeyValue kv : keyValueUpdateSet) { - size += kv.getSize(); - } - - // Size of the guard - size += guard.getSize(); - - return size; - } - - - public void encode(ByteBuffer bb) { - bb.put(Entry.TypeTransaction); - bb.putLong(seqnum); - bb.putLong(machineid); - - bb.putInt(keyValueUpdateSet.size()); - for (KeyValue kv : keyValueUpdateSet) { - kv.encode(bb); - } - - guard.encode(bb); - } - - static Entry decode(Slot slot, ByteBuffer bb) { - long seqnum = bb.getLong(); - long machineid = bb.getLong(); - int numberOfKeys = bb.getInt(); - - Set kvSet = new HashSet(); - for (int i = 0; i < numberOfKeys; i++) { - KeyValue kv = KeyValue.decode(bb); - kvSet.add(kv); - } - - Guard guard = Guard.decode(bb); - - return new Transaction(slot, seqnum, machineid, kvSet, guard); - } - - public Entry getCopy(Slot s) { - return new Transaction(s, seqnum, machineid, keyValueUpdateSet, guard); - } -} \ No newline at end of file diff --git a/src2/java/iotcloud/issues.txt b/src2/java/iotcloud/issues.txt deleted file mode 100644 index 4c246b6..0000000 --- a/src2/java/iotcloud/issues.txt +++ /dev/null @@ -1,2 +0,0 @@ -1) add better resizing support...gets stuck when it is full now... -2) Transaction does not check arbitrator is the same for all keys and guards \ No newline at end of file diff --git a/src2/script/C.cfg b/src2/script/C.cfg deleted file mode 100644 index 6165d83..0000000 --- a/src2/script/C.cfg +++ /dev/null @@ -1,37 +0,0 @@ -indent_with_tabs = 2 -indent_cmt_with_tabs = True -indent_columns = 2 -indent_class = True -output_tab_size = 2 -nl_if_brace = Remove -nl_brace_else = Remove -nl_elseif_brace = Remove -nl_struct_brace = Remove -nl_union_brace = Remove -nl_fcall_brace = Remove -nl_for_brace = Remove -nl_fdef_brace = Remove -nl_while_brace = Remove -nl_do_brace = Remove -nl_brace_while = Remove -nl_switch_brace = Remove -nl_before_case = True -nl_try_brace = Remove -nl_catch_brace = Remove -nl_brace_catch = Remove -sp_func_proto_paren = Remove -sp_func_def_paren = Remove -sp_inside_fparens = remove -sp_inside_fparen = remove -sp_func_call_paren = Remove -sp_fparen_brace = Add -sp_sparen_brace = Add -sp_paren_brace = Add -sp_else_brace = Add -sp_brace_else = Add -sp_catch_brace = Add -sp_brace_catch = Add -sp_try_brace = Add -sp_after_sparen = Add -sp_cond_colon = remove -sp_cond_question = remove diff --git a/src2/script/java.cfg b/src2/script/java.cfg deleted file mode 100644 index 6165d83..0000000 --- a/src2/script/java.cfg +++ /dev/null @@ -1,37 +0,0 @@ -indent_with_tabs = 2 -indent_cmt_with_tabs = True -indent_columns = 2 -indent_class = True -output_tab_size = 2 -nl_if_brace = Remove -nl_brace_else = Remove -nl_elseif_brace = Remove -nl_struct_brace = Remove -nl_union_brace = Remove -nl_fcall_brace = Remove -nl_for_brace = Remove -nl_fdef_brace = Remove -nl_while_brace = Remove -nl_do_brace = Remove -nl_brace_while = Remove -nl_switch_brace = Remove -nl_before_case = True -nl_try_brace = Remove -nl_catch_brace = Remove -nl_brace_catch = Remove -sp_func_proto_paren = Remove -sp_func_def_paren = Remove -sp_inside_fparens = remove -sp_inside_fparen = remove -sp_func_call_paren = Remove -sp_fparen_brace = Add -sp_sparen_brace = Add -sp_paren_brace = Add -sp_else_brace = Add -sp_brace_else = Add -sp_catch_brace = Add -sp_brace_catch = Add -sp_try_brace = Add -sp_after_sparen = Add -sp_cond_colon = remove -sp_cond_question = remove diff --git a/src2/script/makefile b/src2/script/makefile deleted file mode 100644 index ac2da6e..0000000 --- a/src2/script/makefile +++ /dev/null @@ -1,4 +0,0 @@ -tabbing: - uncrustify -c java.cfg --no-backup $$(find .. -name "*.java") - uncrustify -c C.cfg --no-backup $$(find .. -name "*.cpp") - uncrustify -c C.cfg --no-backup $$(find .. -name "*.h") diff --git a/src2/server/.dir-locals.el b/src2/server/.dir-locals.el deleted file mode 100644 index e166a2e..0000000 --- a/src2/server/.dir-locals.el +++ /dev/null @@ -1,2 +0,0 @@ -((nil . ((indent-tabs-mode . t)))) - diff --git a/src2/server/Makefile b/src2/server/Makefile deleted file mode 100644 index 8eee1fa..0000000 --- a/src2/server/Makefile +++ /dev/null @@ -1,15 +0,0 @@ -CPPFLAGS=-O0 -g -Wall - -all: iotcloud.fcgi - -iotcloud.fcgi: iotcloud.o iotquery.o - g++ $(CPPFLAGS) -o iotcloud.fcgi iotcloud.o iotquery.o -lfcgi -lfcgi++ - -iotcloud.o: iotcloud.cpp iotquery.h - g++ $(CPPFLAGS) -c -o iotcloud.o iotcloud.cpp - -iotquery.o: iotquery.cpp iotquery.h - g++ $(CPPFLAGS) -c -o iotquery.o iotquery.cpp - -clean: - rm *.o iotcloud.fcgi diff --git a/src2/server/README.txt b/src2/server/README.txt deleted file mode 100644 index 6eb138f..0000000 --- a/src2/server/README.txt +++ /dev/null @@ -1,32 +0,0 @@ -1) Requires apache2 -2) Requires fastcgi (libapache2-mod-fastcgi and libfcgi-dev) - -Setup on ubuntu -1) Install modules - -2) Add .htaccess file in /var/www/html -RewriteEngine on -RewriteBase / -SetHandler cgi-script -RewriteRule ^([a-zA-Z0-9._]*\.iotcloud/([a-zA-Z0-9._]*))$ /cgi-bin/iotcloud.fcgi/$1 - -3) Create account directory. For example, create the directory test.iotcloud in /var/www/html - -- To password protect, create the following .htaccess file in the account directory: -AuthType Basic -AuthName "Private" -AuthUserFile /var/www/html/foo.iotcloud/.htpasswd -Require valid-user - -4) In apache2.conf, add to the /var/www directory section: -AllowOverride FileInfo AuthConfig - -5) In the sites-enabled/000-default.conf file, add the line: -SetEnv IOTCLOUD_ROOT /iotcloud/ - -6) Create the /iotcloud directory. - -7) Create the account directory in the /iotcloud directory. For example, test.iotcloud and give it permissions that the apache daemon can write to. - -8) Compile cloud server by typing make - -9) Copy it to the cgi-bin directory. diff --git a/src2/server/iotcloud.cpp b/src2/server/iotcloud.cpp deleted file mode 100644 index bb9eff8..0000000 --- a/src2/server/iotcloud.cpp +++ /dev/null @@ -1,40 +0,0 @@ -#include -#include "iotquery.h" - -using namespace std; - - -int main(void) { - // Backup the stdio streambufs - streambuf * cin_streambuf = cin.rdbuf(); - streambuf * cout_streambuf = cout.rdbuf(); - streambuf * cerr_streambuf = cerr.rdbuf(); - - FCGX_Request request; - - FCGX_Init(); - FCGX_InitRequest(&request, 0, 0); - - while (FCGX_Accept_r(&request) == 0) { - fcgi_streambuf cin_fcgi_streambuf(request.in); - fcgi_streambuf cout_fcgi_streambuf(request.out); - fcgi_streambuf cerr_fcgi_streambuf(request.err); - - cin.rdbuf(&cin_fcgi_streambuf); - cout.rdbuf(&cout_fcgi_streambuf); - cerr.rdbuf(&cerr_fcgi_streambuf); - - IoTQuery * iotquery=new IoTQuery(&request); - iotquery->processQuery(); - - delete iotquery; - } - - // restore stdio streambufs - cin.rdbuf(cin_streambuf); - cout.rdbuf(cout_streambuf); - cerr.rdbuf(cerr_streambuf); - - return 0; -} - diff --git a/src2/server/iotquery.cpp b/src2/server/iotquery.cpp deleted file mode 100644 index 0b1c4b3..0000000 --- a/src2/server/iotquery.cpp +++ /dev/null @@ -1,517 +0,0 @@ -#include "iotquery.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include - -using namespace std; - -const char * query_str="QUERY_STRING"; -const char * uri_str="REQUEST_URI"; -const char * method_str="REQUEST_METHOD"; -const char * iotcloudroot_str="IOTCLOUD_ROOT"; -const char * length_str="CONTENT_LENGTH"; - -IoTQuery::IoTQuery(FCGX_Request *request) : - request(request), - data(NULL), - directory(NULL), - uri(NULL), - query(NULL), - method(NULL), - iotcloudroot(NULL), - length(0), - oldestentry(0), - newestentry(0), - requestsequencenumber(0), - numqueueentries(DEFAULT_SIZE), - fd(-1), - reqGetSlot(false), - reqPutSlot(false), - reqSetSalt(false), - reqGetSalt(false) { -} - -IoTQuery::~IoTQuery() { - if (fd >= 0) - close(fd); - if (directory) - delete directory; - if (data) - delete data; -} - -/** - * Returns true if the account directory exists. - */ - -bool IoTQuery::checkDirectory() { - struct stat s; - int err=stat(directory, &s); - if (-1 == err) - return false; - return S_ISDIR(s.st_mode); -} - -/** - * Decodes query string from client. Extracts type of request, - * sequence number, and whether the request changes the number of - * slots. - */ - -void IoTQuery::decodeQuery() { - int len=strlen(query); - char * str=new char[len+1]; - memcpy(str, query, len+1); - char *tok_ptr=str; - - /* Parse commands */ - char *command=strsep(&tok_ptr, "&"); - if (strncmp(command, "req=putslot", 11) == 0) - reqPutSlot = true; - else if (strncmp(command, "req=getslot", 11) == 0) - reqGetSlot = true; - else if (strncmp(command, "req=setsalt", 11) == 0) - reqSetSalt = true; - else if (strncmp(command, "req=getsalt", 11) == 0) - reqGetSalt = true; - - /* Load Sequence Number for request */ - char *sequencenumber_str = strsep(&tok_ptr, "&"); - if (sequencenumber_str != NULL && - strncmp(sequencenumber_str, "seq=", 4) == 0) { - sequencenumber_str = strchr(sequencenumber_str, '='); - if (sequencenumber_str != NULL) { - requestsequencenumber = strtoll(sequencenumber_str + 1, NULL, 10); - } - } - - /* don't allow a really old sequence number */ - if (requestsequencenumber < oldestentry) - requestsequencenumber = oldestentry; - - /* Update size if we get request */ - char * numqueueentries_str = tok_ptr; - if (numqueueentries_str != NULL && - strncmp(numqueueentries_str, "max=", 4) == 0) { - numqueueentries_str = strchr(numqueueentries_str, '=') + 1; - numqueueentries = strtoll(numqueueentries_str, NULL, 10); - } - - delete str; -} - -/** - * Helper function to write data to file. - */ - -void doWrite(int fd, char *data, long long length) { - long long offset=0; - do { - long long byteswritten=write(fd, &data[offset], length); - if (byteswritten > 0) { - length -= byteswritten; - offset += byteswritten; - } else { - cerr << "Bytes not written" << endl; - if (byteswritten < 0) { - cerr << strerror(errno) << " error writing slot file" << endl; - } - return; - } - } while(length != 0); -} - -/** Helper function to read data from file. */ -bool doRead(int fd, void *buf, int numbytes) { - int offset=0; - char *ptr=(char *)buf; - do { - int bytesread=read(fd, ptr+offset, numbytes); - if (bytesread > 0) { - offset += bytesread; - numbytes -= bytesread; - } else - return false; - } while (numbytes!=0); - return true; -} - -/** - * Function that handles a getSlot request. - */ - -void IoTQuery::getSlot() { - int numrequeststosend = (int)((newestentry-requestsequencenumber)+1); - if (numrequeststosend < 0) - numrequeststosend = 0; - long long numbytes = 0; - int filesizes[numrequeststosend]; - int fdarray[numrequeststosend]; - int index=0; - for(long long seqn = requestsequencenumber; seqn <= newestentry; seqn++, index++) { - struct stat st; - char *filename=getSlotFileName(seqn); - if (stat(filename, &st) == 0) { - fdarray[index]=open(filename, O_RDONLY); - filesizes[index]=st.st_size; - numbytes+=filesizes[index]; - } else { - fdarray[index]=-1; - filesizes[index]=0; - } - delete filename; - } - const char header[]="getslot"; - - /* Size is the header + the payload + space for number of requests - plus sizes of each slot */ - - long long size=sizeof(header)-1+sizeof(numrequeststosend)+4*numrequeststosend+numbytes; - char * response = new char[size]; - long long offset=0; - memcpy(response, header, sizeof(header)-1); - offset+=sizeof(header)-1; - int numreq=htonl(numrequeststosend); - memcpy(response + offset, &numreq, sizeof(numreq)); - offset+=sizeof(numrequeststosend); - for(int i=0; i=0) { - doRead(fdarray[i], response+offset, filesizes[i]); - offset+=filesizes[i]; - } - } - - /* Send the response out to the webserver. */ - sendResponse(response, size); - - /* Delete the response buffer and close the files. */ - delete response; - for(int i=0; i= 0) - close(fdarray[i]); - } -} - -/** - * The method setSalt handles a setSalt request from the client. - */ - -void IoTQuery::setSalt() { - /* Write the slot data we received to a SLOT file */ - char *filename = getSaltFileName(); - int saltfd = open(filename, O_CREAT|O_WRONLY, S_IRUSR| S_IWUSR); - doWrite(saltfd, data, length); - char response[0]; - sendResponse(response, 0); - close(saltfd); - delete filename; -} - -/** - * The method getSalt handles a setSalt request from the client. - */ - -void IoTQuery::getSalt() { - /* Write the slot data we received to a SLOT file */ - char *filename = getSaltFileName(); - int filesize = 0; - struct stat st; - if (stat(filename, &st) == 0) { - filesize=st.st_size; - } else { - delete filename; - return; - } - int saltfd = open(filename, O_RDONLY); - int responsesize = filesize + sizeof(int); - char * response = new char[responsesize]; - doRead(saltfd, response+ sizeof(int), filesize); - int n_filesize=htonl(filesize); - *((int*) response) = n_filesize; - sendResponse(response, responsesize); - close(saltfd); - delete filename; - delete response; -} - -/** - * The method putSlot handles a putSlot request from the client - */ - -void IoTQuery::putSlot() { - /* Check if the request is stale and send update in that case. This - servers as an implicit failure of the request. */ - if (requestsequencenumber!=(newestentry+1)) { - getSlot(); - return; - } - - /* See if we have too many slots and if so, delete the old one */ - int numberofliveslots=(int) ((newestentry-oldestentry)+1); - if (numberofliveslots >= numqueueentries) { - removeOldestSlot(); - } - - /* Write the slot data we received to a SLOT file */ - char *filename = getSlotFileName(requestsequencenumber); - int slotfd = open(filename, O_CREAT|O_WRONLY, S_IRUSR| S_IWUSR); - doWrite(slotfd, data, length); - close(slotfd); - delete filename; - newestentry = requestsequencenumber; - - /* Update the seuqence numbers and other status file information. */ - updateStatusFile(); - - /* Send response acknowledging success */ - char command[]="putslot"; - sendResponse(command, sizeof(command)-1); -} - -/** - * Method sends response. It wraps in appropriate headers for web - * server. - */ - -void IoTQuery::sendResponse(char * bytes, int len) { - cout << "Accept-Ranges: bytes\r\n" - << "Content-Length: " << len << "\r\n" - << "\r\n"; - cout.write(bytes, len); -} - -/** - * Computes the name for a slot file for the given sequence number. - */ - -char * IoTQuery::getSlotFileName(long long seqnum) { - int directorylen=strlen(directory); - - /* Size is 19 digits for ASCII representation of a long + 4 - characters for SLOT string + 1 character for null termination + - directory size*/ - - char * filename=new char[25+directorylen]; - snprintf(filename, 25+directorylen, "%s/SLOT%lld", directory, seqnum); - return filename; -} - -/** - * Computes the name for a salt file - */ - -char * IoTQuery::getSaltFileName() { - int directorylen=strlen(directory); - - /* Size is 4 characters for SALT string + 1 character for null - termination + directory size*/ - - char * filename=new char[6+directorylen]; - snprintf(filename, 6+directorylen, "%s/SALT", directory); - return filename; -} - -/** - * Removes the oldest slot file - */ - -void IoTQuery::removeOldestSlot() { - if (oldestentry!=0) { - char * filename=getSlotFileName(oldestentry); - unlink(filename); - delete filename; - } - oldestentry++; -} - -/** - * Processes the query sent to the fastcgi handler. - */ - -void IoTQuery::processQuery() { - getQuery(); - getDirectory(); - readData(); - - /* Verify that we receive a post request. */ - if (strncmp(method, "POST", 4) != 0) { - cerr << "Not POST Request" << endl; - return; - } - - /* Make sure the directory is okay. */ - if (directory == NULL || - !checkDirectory()) { - cerr << "Directory " << directory << " does not exist" << endl; - return; - } - - /* Get queue state from the status file. If it doesn't exist, - create it. */ - if (!openStatusFile()) { - cerr << "Failed to open status file" << endl; - return; - } - - /* Lock status file to keep other requests out. */ - flock(fd, LOCK_EX); - - /* Decode query. */ - decodeQuery(); - - /* Handle request. */ - if (reqGetSlot) - getSlot(); - else if (reqPutSlot) - putSlot(); - else if (reqSetSalt) - setSalt(); - else if (reqGetSalt) - getSalt(); - else { - cerr << "No recognized request" << endl; - return; - } -} - -/** - * Reads in data for request. This is used for the slot to be - * inserted. - */ - -void IoTQuery::readData() { - if (length) { - data = new char[length+1]; - memset(data, 0, length+1); - cin.read(data, length); - } - do { - char dummy; - cin >> dummy; - } while (!cin.eof()); -} - - -/** - * Reads relevant environmental variables to find out the request. - */ - -void IoTQuery::getQuery() { - uri = FCGX_GetParam(uri_str, request->envp); - query = FCGX_GetParam(query_str, request->envp); - method = FCGX_GetParam(method_str, request->envp); - iotcloudroot = FCGX_GetParam(iotcloudroot_str, request->envp); - - /** We require the content-length header to be sent. */ - char * reqlength = FCGX_GetParam(length_str, request->envp); - if (reqlength) { - length=strtoll(reqlength, NULL, 10); - } else { - length=0; - } -} - -/** - * Initializes directory field from environmental variables. - */ - -void IoTQuery::getDirectory() { - char * split = strchr((char *)uri, '?'); - if (split == NULL) - return; - int split_len = (int) (split-uri); - int rootdir_len = strlen(iotcloudroot); - int directory_len = split_len + rootdir_len + 1; - directory = new char[directory_len]; - memcpy(directory, iotcloudroot, rootdir_len); - memcpy(directory + rootdir_len, uri, split_len); - directory[directory_len-1]=0; -} - -/** - * Helper function that is used to read the status file. - */ - -int doread(int fd, void *ptr, size_t count, off_t offset) { - do { - size_t bytesread=pread(fd, ptr, count, offset); - if (bytesread==count) { - return 1; - } else if (bytesread==0) { - return 0; - } - } while(1); -} - - -/** - * Writes the current state to the status file. - */ - -void IoTQuery::updateStatusFile() { - pwrite(fd, &numqueueentries, sizeof(numqueueentries), OFFSET_MAX); - pwrite(fd, &oldestentry, sizeof(oldestentry), OFFSET_OLD); - pwrite(fd, &newestentry, sizeof(newestentry), OFFSET_NEW); -} - -/** - * Reads in queue state from the status file. Returns true if - * successful. - */ - -bool IoTQuery::openStatusFile() { - char statusfile[]="queuestatus"; - int len=strlen(directory); - - char * filename=new char[len+sizeof(statusfile)+2]; - memcpy(filename, directory, len); - filename[len]='/'; - memcpy(filename+len+1, statusfile, sizeof(statusfile)); - filename[len+sizeof(statusfile)+1]=0; - fd=open(filename, O_CREAT| O_RDWR, S_IRUSR| S_IWUSR); - delete filename; - - if (fd < 0) { - cerr << strerror(errno) << " error opening statusfile" << endl; - return false; - } - - /* Read in queue size, oldest sequence number, and newest sequence number. */ - int size; - int needwrite=0; - if (doread(fd, &size, sizeof(size), OFFSET_MAX)) - numqueueentries=size; - else - needwrite=1; - - long long entry; - if (doread(fd, &entry, sizeof(entry), OFFSET_OLD)) - oldestentry=entry; - else - needwrite=1; - - if (doread(fd, &entry, sizeof(entry), OFFSET_NEW)) - newestentry=entry; - else - needwrite=1; - - if (needwrite) - updateStatusFile(); - - return true; -} - - diff --git a/src2/server/iotquery.h b/src2/server/iotquery.h deleted file mode 100644 index ae39366..0000000 --- a/src2/server/iotquery.h +++ /dev/null @@ -1,68 +0,0 @@ -#ifndef IOTQUERY_H -#define IOTQUERY_H -#include -#include "fcgio.h" -#include "fcgi_stdio.h" - -#define DEFAULT_SIZE 128 -#define OFFSET_MAX 0 -#define OFFSET_OLD 4 -#define OFFSET_NEW 12 - -class IoTQuery { -public: - IoTQuery(FCGX_Request * request); - ~IoTQuery(); - void processQuery(); - -private: - void sendResponse(char *data, int length); - void getQuery(); - void getDirectory(); - void readData(); - bool checkDirectory(); - bool openStatusFile(); - void updateStatusFile(); - void decodeQuery(); - void getSlot(); - void putSlot(); - void setSalt(); - void getSalt(); - void removeOldestSlot(); - char * getSlotFileName(long long); - char * getSaltFileName(); - - FCGX_Request * request; - char *data; - /* Directory slot files are placed in. */ - char *directory; - /* Full URI from Apache */ - const char * uri; - /* Query portion of URI */ - const char * query; - /* Type of request: GET or PUT */ - const char * method; - /* Root directory for all accounts */ - const char * iotcloudroot; - /* Expected length of data from client */ - long long length; - /* Sequence number for oldest slot */ - long long oldestentry; - /* Sequence number for newest slot */ - long long newestentry; - /* Sequence number from request */ - long long requestsequencenumber; - /* Size of queue */ - int numqueueentries; - /* fd for queuestatus file */ - int fd; - /* Is the request to get a slot? */ - bool reqGetSlot; - /* Is the request to put a slot? */ - bool reqPutSlot; - /* Is the request to set the salt? */ - bool reqSetSalt; - /* Is the request to get the salt? */ - bool reqGetSalt; -}; -#endif -- 2.34.1