edits
[iotcloud.git] / version2 / src / C / CloudComm.cc
1 #include "CloudComm.h"
2 #include "TimingSingleton.h"
3 #include "SecureRandom.h"
4 #include "IoTString.h"
5 #include "Error.h"
6 #include "URL.h"
7 #include "Mac.h"
8 #include "Table.h"
9 #include "Slot.h"
10 #include "Crypto.h"
11 #include "ByteBuffer.h"
12 #include "aes.h"
13 #include <sys/types.h>
14 #include <sys/socket.h>
15 #include <arpa/inet.h>
16 #include <netinet/tcp.h>
17 #include <unistd.h>
18 #include <netdb.h>
19
20 /**
21  * Empty Constructor needed for child class.
22  */
23 CloudComm::CloudComm() :
24         baseurl(NULL),
25         key(NULL),
26         mac(NULL),
27         password(NULL),
28         random(NULL),
29         salt(NULL),
30         table(NULL),
31         listeningPort(-1),
32         doEnd(false),
33         timer(TimingSingleton_getInstance()),
34         getslot(new Array<char>("getslot", 7)),
35         putslot(new Array<char>("putslot", 7))
36 {
37 }
38
39 void *threadWrapper(void *cloud) {
40         CloudComm *c = (CloudComm *) cloud;
41         c->localServerWorkerFunction();
42         return NULL;
43 }
44
45 /**
46  * Constructor for actual use. Takes in the url and password.
47  */
48 CloudComm::CloudComm(Table *_table,  IoTString *_baseurl, IoTString *_password, int _listeningPort) :
49         baseurl(new IoTString(_baseurl)),
50         key(NULL),
51         mac(NULL),
52         password(new IoTString(_password)),
53         random(new SecureRandom()),
54         salt(NULL),
55         table(_table),
56         listeningPort(_listeningPort),
57         doEnd(false),
58         timer(TimingSingleton_getInstance()),
59         getslot(new Array<char>("getslot", 7)),
60         putslot(new Array<char>("putslot", 7)) {
61         if (listeningPort > 0) {
62                 pthread_create(&localServerThread, NULL, threadWrapper, this);
63         }
64 }
65
66 CloudComm::~CloudComm() {
67         delete getslot;
68         delete putslot;
69         if (salt)
70                 delete salt;
71         if (password)
72                 delete password;
73         if (random)
74                 delete random;
75         if (baseurl)
76                 delete baseurl;
77         if (mac)
78                 delete mac;
79         if (key)
80                 delete key;
81 }
82
83 /**
84  * Generates Key from password.
85  */
86 AESKey *CloudComm::initKey() {
87         try {
88                 AESKey *key = new AESKey(password->internalBytes(),
89                                                                                                                  salt,
90                                                                                                                  65536,
91                                                                                                                  128);
92                 return key;
93         } catch (Exception *e) {
94                 throw new Error("Failed generating key.");
95         }
96 }
97
98 /**
99  * Inits all the security stuff
100  */
101
102 void CloudComm::initSecurity() {
103         // try to get the salt and if one does not exist set one
104         if (!getSalt()) {
105                 //Set the salt
106                 setSalt();
107         }
108
109         initCrypt();
110 }
111
112 /**
113  * Inits the HMAC generator.
114  */
115 void CloudComm::initCrypt() {
116         if (password == NULL) {
117                 return;
118         }
119         try {
120                 key = initKey();
121                 delete password;
122                 password = NULL;// drop password
123                 mac = new Mac();
124                 mac->init(key);
125         } catch (Exception *e) {
126                 throw new Error("Failed To Initialize Ciphers");
127         }
128 }
129
130 /*
131  * Builds the URL for the given request.
132  */
133 IoTString *CloudComm::buildRequest(bool isput, int64_t sequencenumber, int64_t maxentries) {
134         const char *reqstring = isput ? "req=putslot" : "req=getslot";
135         char *buffer = (char *) malloc(baseurl->length() + 200);
136         memcpy(buffer, baseurl->internalBytes()->internalArray(), baseurl->length());
137         int offset = baseurl->length();
138         offset += sprintf(&buffer[offset], "?%s&seq=%" PRId64, reqstring, sequencenumber);
139         if (maxentries != 0)
140                 sprintf(&buffer[offset], "&max=%" PRId64, maxentries);
141         IoTString *urlstr = new IoTString(buffer);
142         free(buffer);
143         return urlstr;
144 }
145
146 void loopWrite(int fd, char *array, int bytestowrite) {
147         int byteswritten = 0;
148         while (bytestowrite) {
149                 int bytes = write(fd, &array[byteswritten], bytestowrite);
150                 if (bytes >= 0) {
151                         byteswritten += bytes;
152                         bytestowrite -= bytes;
153                 } else {
154                         printf("Error in write\n");
155                         exit(-1);
156                 }
157         }
158 }
159
160 void loopRead(int fd, char *array, int bytestoread) {
161         int bytesread = 0;
162         while (bytestoread) {
163                 int bytes = read(fd, &array[bytesread], bytestoread);
164                 if (bytes >= 0) {
165                         bytesread += bytes;
166                         bytestoread -= bytes;
167                 } else {
168                         printf("Error in read\n");
169                         exit(-1);
170                 }
171         }
172 }
173
174 WebConnection openURL(IoTString *url) {
175         if (url->length() < 7 || memcmp(url->internalBytes()->internalArray(), "http://", 7)) {
176                 printf("BOGUS URL\n");
177                 exit(-1);
178         }
179         int i = 7;
180         for (; i < url->length(); i++)
181                 if (url->get(i) == '/')
182                         break;
183
184         if ( i == url->length()) {
185                 printf("ERROR in openURL\n");
186                 exit(-1);
187         }
188
189         char *host = (char *) malloc(i - 6);
190         memcpy(host, &url->internalBytes()->internalArray()[7], i - 7);
191         host[i - 7] = 0;
192         printf("%s\n", host);
193
194         char *message = (char *)malloc(sizeof("POST  HTTP/1.1\r\n") + sizeof("Host: \r\n") + 2 * url->length());
195
196         /* fill in the parameters */
197         int post = sprintf(message,"POST ");
198         /* copy data */
199         memcpy(&message[post], &url->internalBytes()->internalArray()[i], url->length() - i);
200         int endpost = sprintf(&message[post + url->length() - i], " HTTP/1.1\r\n");
201
202         int hostlen = sprintf(&message[endpost + post + url->length() - i], "Host: ");
203         memcpy(&message[endpost + post + url->length() + hostlen - i], host, i - 7);
204         sprintf(&message[endpost + post + url->length() + hostlen - 7], "\r\n");
205
206         /* create the socket */
207         int sockfd = socket(AF_INET, SOCK_STREAM, 0);
208         if (sockfd < 0) {printf("ERROR opening socket\n"); exit(-1);}
209
210         /* lookup the ip address */
211         struct hostent *server = gethostbyname(host);
212         free(host);
213
214         if (server == NULL) {printf("ERROR, no such host"); exit(-1);}
215
216         /* fill in the structure */
217         struct sockaddr_in serv_addr;
218
219         memset(&serv_addr,0,sizeof(serv_addr));
220         serv_addr.sin_family = AF_INET;
221         serv_addr.sin_port = htons(80);
222         memcpy(&serv_addr.sin_addr.s_addr,server->h_addr,server->h_length);
223
224         /* connect the socket */
225         if (connect(sockfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr)) < 0) {
226                 printf("ERROR connecting");
227                 exit(-1);
228         }
229
230         /* send the request */
231         int total = strlen(message);
232         loopWrite(sockfd, message, total);
233         free(message);
234         return (WebConnection) {sockfd, -1};
235 }
236
237 int createSocket(IoTString *name, int port) {
238         char *host = (char *) malloc(name->length() + 1);
239         memcpy(host, name->internalBytes()->internalArray(), name->length());
240         host[name->length()] = 0;
241         printf("%s\n", host);
242         /* How big is the message? */
243
244         /* create the socket */
245         int sockfd = socket(AF_INET, SOCK_STREAM, 0);
246         if (sockfd < 0) {printf("ERROR opening socket\n"); exit(-1);}
247
248         /* lookup the ip address */
249         struct hostent *server = gethostbyname(host);
250         free(host);
251
252         if (server == NULL) {printf("ERROR, no such host"); exit(-1);}
253
254         /* fill in the structure */
255         struct sockaddr_in serv_addr;
256
257         memset(&serv_addr,0,sizeof(serv_addr));
258         serv_addr.sin_family = AF_INET;
259         serv_addr.sin_port = htons(port);
260         memcpy(&serv_addr.sin_addr.s_addr,server->h_addr,server->h_length);
261
262         /* connect the socket */
263         if (connect(sockfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr)) < 0) {
264                 printf("ERROR connecting");
265                 exit(-1);
266         }
267
268         return sockfd;
269 }
270
271 int createSocket(int port) {
272         int fd;
273         struct sockaddr_in sin;
274
275         bzero(&sin, sizeof(sin));
276         sin.sin_family = AF_INET;
277         sin.sin_port = htons(port);
278         sin.sin_addr.s_addr = htonl(INADDR_ANY);
279         fd = socket(AF_INET, SOCK_STREAM, 0);
280         int n = 1;
281         if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&n, sizeof (n)) < 0) {
282                 close(fd);
283                 printf("Create Socket Error\n");
284                 exit(-1);
285         }
286         if (bind(fd, (struct sockaddr *) &sin, sizeof(sin)) < 0) {
287                 close(fd);
288                 exit(-1);
289         }
290         if (listen(fd, 5) < 0) {
291                 close(fd);
292                 exit(-1);
293         }
294         return fd;
295 }
296
297 int acceptSocket(int socket) {
298         struct sockaddr_in sin;
299         unsigned int sinlen = sizeof(sin);
300         int newfd = accept(socket, (struct sockaddr *)&sin, &sinlen);
301         int flag = 1;
302         setsockopt(newfd, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(flag));
303         if (newfd < 0) {
304                 printf("Accept Error\n");
305                 exit(-1);
306         }
307         return newfd;
308 }
309
310 void writeSocketData(int fd, Array<char> *data) {
311         loopWrite(fd, data->internalArray(), data->length());
312 }
313
314 void writeSocketInt(int fd, int32_t value) {
315         char array[4];
316         array[0] = value >> 24;
317         array[1] = (value >> 16) & 0xff;
318         array[2] = (value >> 8) & 0xff;
319         array[3] = value & 0xff;
320         loopWrite(fd, array, 4);
321 }
322
323 int readSocketInt(int fd) {
324         char array[4];
325         loopRead(fd, array, 4);
326         return (((int32_t)(unsigned char) array[0]) << 24) |
327                                  (((int32_t)(unsigned char) array[1]) << 16) |
328                                  (((int32_t)(unsigned char) array[2]) << 8) |
329                                  ((int32_t)(unsigned char) array[3]);
330 }
331
332 void readSocketData(int fd, Array<char> *data) {
333         loopRead(fd, data->internalArray(), data->length());
334 }
335
336 void writeURLDataAndClose(WebConnection *wc, Array<char> *data) {
337         dprintf(wc->fd, "Content-Length: %d\r\n\r\n", data->length());
338         loopWrite(wc->fd, data->internalArray(), data->length());
339 }
340
341 void closeURLReq(WebConnection *wc) {
342         dprintf(wc->fd, "\r\n");
343 }
344
345 void readURLData(WebConnection *wc, Array<char> *output) {
346         loopRead(wc->fd, output->internalArray(), output->length());
347 }
348
349 int readURLInt(WebConnection *wc) {
350         char array[4];
351         loopRead(wc->fd, array, 4);
352         return (((int32_t)(unsigned char) array[0]) << 24) |
353                                  (((int32_t)(unsigned char) array[1]) << 16) |
354                                  (((int32_t)(unsigned char) array[2]) << 8) |
355                                  ((int32_t)(unsigned char) array[3]);
356 }
357
358 void readLine(WebConnection *wc, char *response, int numBytes) {
359         int offset = 0;
360         char newchar;
361         while (true) {
362                 int bytes = read(wc->fd, &newchar, 1);
363                 if (bytes <= 0)
364                         break;
365                 if (offset == (numBytes - 1)) {
366                         printf("Response too long");
367                         exit(-1);
368                 }
369                 response[offset++] = newchar;
370                 if (newchar == '\n')
371                         break;
372         }
373         response[offset] = 0;
374 }
375
376 int getResponseCode(WebConnection *wc) {
377         char response[600];
378         readLine(wc, response, sizeof(response));
379         int ver1 = 0, ver2 = 0, respcode = 0;
380         sscanf(response, "HTTP/%d.%d %d", &ver1, &ver2, &respcode);
381         printf("Response code %d\n", respcode);
382         return respcode;
383 }
384
385 void readHeaders(WebConnection *wc) {
386         char response[600];
387         int numBytes;
388
389         while (true) {
390                 readLine(wc, response, sizeof(response));
391                 if (response[0] == '\r')
392                         return;
393                 else if (memcmp(response, "Content-Length:", sizeof("Content-Length:") - 1) == 0) {
394                         sscanf(response, "Content-Length: %d", &numBytes);
395                         wc->numBytes = numBytes;
396                 }
397         }
398 }
399
400 void CloudComm::setSalt() {
401         if (salt != NULL) {
402                 // Salt already sent to server so don't set it again
403                 return;
404         }
405
406         WebConnection wc = {-1, -1};
407         try {
408                 Array<char> *saltTmp = new Array<char>(CloudComm_SALT_SIZE);
409                 random->nextBytes(saltTmp);
410
411                 char *buffer = (char *) malloc(baseurl->length() + 100);
412                 memcpy(buffer, baseurl->internalBytes()->internalArray(), baseurl->length());
413                 int offset = baseurl->length();
414                 offset += sprintf(&buffer[offset], "?req=setsalt");
415                 IoTString *urlstr = new IoTString(buffer);
416                 free(buffer);
417
418                 timer->startTime();
419                 wc = openURL(urlstr);
420                 delete urlstr;
421                 writeURLDataAndClose(&wc, saltTmp);
422
423                 int responsecode = getResponseCode(&wc);
424                 if (responsecode != HttpURLConnection_HTTP_OK) {
425                         throw new Error("Invalid response");
426                 }
427                 close(wc.fd);
428
429                 timer->endTime();
430                 salt = saltTmp;
431         } catch (Exception *e) {
432                 timer->endTime();
433                 throw new ServerException("Failed setting salt", ServerException_TypeConnectTimeout);
434         }
435 }
436
437 bool CloudComm::getSalt() {
438         WebConnection wc = {-1, -1};
439         IoTString *urlstr = NULL;
440
441         try {
442                 char *buffer = (char *) malloc(baseurl->length() + 100);
443                 memcpy(buffer, baseurl->internalBytes()->internalArray(), baseurl->length());
444                 int offset = baseurl->length();
445                 offset += sprintf(&buffer[offset], "?req=getsalt");
446                 urlstr = new IoTString(buffer);
447                 free(buffer);
448         } catch (Exception *e) {
449                 throw new Error("getSlot failed");
450         }
451         try {
452                 timer->startTime();
453                 wc = openURL(urlstr);
454                 delete urlstr;
455                 urlstr = NULL;
456                 closeURLReq(&wc);
457                 timer->endTime();
458         } catch (SocketTimeoutException *e) {
459                 if (urlstr)
460                         delete urlstr;
461                 timer->endTime();
462                 throw new ServerException("getSalt failed", ServerException_TypeConnectTimeout);
463         } catch (Exception *e) {
464                 if (urlstr)
465                         delete urlstr;
466                 throw new Error("getSlot failed");
467         }
468
469         try {
470                 timer->startTime();
471                 int responsecode = getResponseCode(&wc);
472                 readHeaders(&wc);
473                 if (responsecode != HttpURLConnection_HTTP_OK) {
474                         throw new Error("Invalid response");
475                 }
476                 if (wc.numBytes == 0) {
477                         timer->endTime();
478                         close(wc.fd);
479                         return false;
480                 }
481
482
483                 int salt_length = readURLInt(&wc);
484                 Array<char> *tmp = new Array<char>(salt_length);
485                 readURLData(&wc, tmp);
486                 close(wc.fd);
487
488                 salt = tmp;
489                 timer->endTime();
490                 return true;
491         } catch (SocketTimeoutException *e) {
492                 timer->endTime();
493                 throw new ServerException("getSalt failed", ServerException_TypeInputTimeout);
494         } catch (Exception *e) {
495                 throw new Error("getSlot failed");
496         }
497 }
498
499 Array<char> *CloudComm::createIV(int64_t machineId, int64_t localSequenceNumber) {
500         ByteBuffer *buffer = ByteBuffer_allocate(CloudComm_IV_SIZE);
501         buffer->putLong(machineId);
502         int64_t localSequenceNumberShifted = localSequenceNumber << 16;
503         buffer->putLong(localSequenceNumberShifted);
504         return buffer->array();
505 }
506
507 Array<char> *AESEncrypt(Array<char> *ivBytes, AESKey *key, Array<char> *data) {
508         Array<char> *output = new Array<char>(data->length());
509         aes_encrypt_ctr((BYTE *)data->internalArray(), data->length(), (BYTE *) output->internalArray(), (WORD *)key->getKeySchedule(), key->getKey()->length() * 8, (BYTE *)ivBytes->internalArray());
510         return output;
511 }
512
513 Array<char> *AESDecrypt(Array<char> *ivBytes, AESKey *key, Array<char> *data) {
514         Array<char> *output = new Array<char>(data->length());
515         aes_decrypt_ctr((BYTE *)data->internalArray(), data->length(), (BYTE *)output->internalArray(), (WORD *)key->getKeySchedule(), key->getKey()->length() * 8, (BYTE *)ivBytes->internalArray());
516         return output;
517 }
518
519 Array<char> *CloudComm::encryptSlotAndPrependIV(Array<char> *rawData, Array<char> *ivBytes) {
520         try {
521                 Array<char> *encryptedBytes = AESEncrypt(ivBytes, key, rawData);
522                 Array<char> *chars = new Array<char>(encryptedBytes->length() + CloudComm_IV_SIZE);
523                 System_arraycopy(ivBytes, 0, chars, 0, ivBytes->length());
524                 System_arraycopy(encryptedBytes, 0, chars, CloudComm_IV_SIZE, encryptedBytes->length());
525                 delete encryptedBytes;
526                 return chars;
527         } catch (Exception *e) {
528                 throw new Error("Failed To Encrypt");
529         }
530 }
531
532 Array<char> *CloudComm::stripIVAndDecryptSlot(Array<char> *rawData) {
533         try {
534                 Array<char> *ivBytes = new Array<char>(CloudComm_IV_SIZE);
535                 Array<char> *encryptedBytes = new Array<char>(rawData->length() - CloudComm_IV_SIZE);
536                 System_arraycopy(rawData, 0, ivBytes, 0, CloudComm_IV_SIZE);
537                 System_arraycopy(rawData, CloudComm_IV_SIZE, encryptedBytes, 0, encryptedBytes->length());
538                 Array<char> * data = AESDecrypt(ivBytes, key, encryptedBytes);
539                 delete encryptedBytes;
540                 delete ivBytes;
541                 return data;
542         } catch (Exception *e) {
543                 throw new Error("Failed To Decrypt");
544         }
545 }
546
547 /*
548  * API for putting a slot into the queue.  Returns NULL on success.
549  * On failure, the server will send slots with newer sequence
550  * numbers.
551  */
552 Array<Slot *> *CloudComm::putSlot(Slot *slot, int max) {
553         WebConnection wc = {-1, -1};
554         try {
555                 if (salt == NULL) {
556                         if (!getSalt()) {
557                                 throw new ServerException("putSlot failed", ServerException_TypeSalt);
558                         }
559                         initCrypt();
560                 }
561
562                 int64_t sequencenumber = slot->getSequenceNumber();
563                 Array<char> *slotBytes = slot->encode(mac);
564                 Array<char> * ivBytes = slot->getSlotCryptIV();
565                 Array<char> *chars = encryptSlotAndPrependIV(slotBytes, ivBytes);
566                 delete ivBytes;
567                 delete slotBytes;
568                 IoTString *url = buildRequest(true, sequencenumber, max);
569                 timer->startTime();
570                 wc = openURL(url);
571                 delete url;
572                 writeURLDataAndClose(&wc, chars);
573                 delete chars;
574                 timer->endTime();
575         } catch (ServerException *e) {
576                 timer->endTime();
577                 throw e;
578         } catch (SocketTimeoutException *e) {
579                 timer->endTime();
580                 throw new ServerException("putSlot failed", ServerException_TypeConnectTimeout);
581         } catch (Exception *e) {
582                 throw new Error("putSlot failed");
583         }
584
585         Array<char> *resptype = NULL;
586         try {
587                 int respcode = getResponseCode(&wc);
588                 readHeaders(&wc);
589                 timer->startTime();
590                 resptype = new Array<char>(7);
591                 readURLData(&wc, resptype);
592                 timer->endTime();
593
594                 if (resptype->equals(getslot)) {
595                         delete resptype;
596                         Array<Slot *> *tmp = processSlots(&wc);
597                         close(wc.fd);
598                         return tmp;
599                 } else if (resptype->equals(putslot)) {
600                         delete resptype;
601                         close(wc.fd);
602                         return NULL;
603                 } else {
604                         delete resptype;
605                         close(wc.fd);
606                         throw new Error("Bad response to putslot");
607                 }
608         } catch (SocketTimeoutException *e) {
609                 if (resptype != NULL)
610                         delete resptype;
611                 timer->endTime();
612                 close(wc.fd);
613                 throw new ServerException("putSlot failed", ServerException_TypeInputTimeout);
614         } catch (Exception *e) {
615                 if (resptype != NULL)
616                         delete resptype;
617                 throw new Error("putSlot failed");
618         }
619 }
620
621 /**
622  * Request the server to send all slots with the given
623  * sequencenumber or newer->
624  */
625 Array<Slot *> *CloudComm::getSlots(int64_t sequencenumber) {
626         WebConnection wc = {-1, -1};
627         try {
628                 if (salt == NULL) {
629                         if (!getSalt()) {
630                                 throw new ServerException("getSlots failed", ServerException_TypeSalt);
631                         }
632                         initCrypt();
633                 }
634
635                 IoTString *url = buildRequest(false, sequencenumber, 0);
636                 timer->startTime();
637                 wc = openURL(url);
638                 delete url;
639                 closeURLReq(&wc);
640                 timer->endTime();
641         } catch (SocketTimeoutException *e) {
642                 timer->endTime();
643                 throw new ServerException("getSlots failed", ServerException_TypeConnectTimeout);
644         } catch (ServerException *e) {
645                 timer->endTime();
646
647                 throw e;
648         } catch (Exception *e) {
649                 throw new Error("getSlots failed");
650         }
651
652         try {
653                 timer->startTime();
654                 int responsecode = getResponseCode(&wc);
655                 readHeaders(&wc);
656                 Array<char> *resptype = new Array<char>(7);
657                 readURLData(&wc, resptype);
658                 timer->endTime();
659                 if (!resptype->equals(getslot))
660                         throw new Error("Bad Response: ");
661
662                 delete resptype;
663                 Array<Slot *> *tmp = processSlots(&wc);
664                 close(wc.fd);
665                 return tmp;
666         } catch (SocketTimeoutException *e) {
667                 timer->endTime();
668                 close(wc.fd);
669                 throw new ServerException("getSlots failed", ServerException_TypeInputTimeout);
670         } catch (Exception *e) {
671                 throw new Error("getSlots failed");
672         }
673 }
674
675 /**
676  * Method that actually handles building Slot objects from the
677  * server response.  Shared by both putSlot and getSlots.
678  */
679 Array<Slot *> *CloudComm::processSlots(WebConnection *wc) {
680         int numberofslots = readURLInt(wc);
681         Array<int> *sizesofslots = new Array<int>(numberofslots);
682         Array<Slot *> *slots = new Array<Slot *>(numberofslots);
683
684         for (int i = 0; i < numberofslots; i++)
685                 sizesofslots->set(i, readURLInt(wc));
686         for (int i = 0; i < numberofslots; i++) {
687                 Array<char> *rawData = new Array<char>(sizesofslots->get(i));
688                 readURLData(wc, rawData);
689                 Array<char> *data = stripIVAndDecryptSlot(rawData);
690                 delete rawData;
691                 slots->set(i, Slot_decode(table, data, mac));
692                 delete data;
693         }
694         delete sizesofslots;
695         return slots;
696 }
697
698 Array<char> *CloudComm::sendLocalData(Array<char> *sendData, int64_t localSequenceNumber, IoTString *host, int port) {
699         if (salt == NULL)
700                 return NULL;
701         try {
702                 printf("Passing Locally\n");
703                 mac->update(sendData, 0, sendData->length());
704                 Array<char> *genmac = mac->doFinal();
705                 Array<char> *totalData = new Array<char>(sendData->length() + genmac->length());
706                 System_arraycopy(sendData, 0, totalData, 0, sendData->length());
707                 System_arraycopy(genmac, 0, totalData, sendData->length(), genmac->length());
708
709                 // Encrypt the data for sending
710                 Array<char> *iv = createIV(table->getMachineId(), table->getLocalSequenceNumber());
711                 Array<char> *encryptedData = encryptSlotAndPrependIV(totalData, iv);
712
713                 // Open a TCP socket connection to a local device
714                 int socket = createSocket(host, port);
715
716                 timer->startTime();
717                 // Send data to output (length of data, the data)
718                 writeSocketInt(socket, encryptedData->length());
719                 writeSocketData(socket, encryptedData);
720
721                 int lengthOfReturnData = readSocketInt(socket);
722                 Array<char> *returnData = new Array<char>(lengthOfReturnData);
723                 readSocketData(socket, returnData);
724                 timer->endTime();
725                 returnData = stripIVAndDecryptSlot(returnData);
726
727                 // We are done with this socket
728                 close(socket);
729                 mac->update(returnData, 0, returnData->length() - CloudComm_HMAC_SIZE);
730                 Array<char> *realmac = mac->doFinal();
731                 Array<char> *recmac = new Array<char>(CloudComm_HMAC_SIZE);
732                 System_arraycopy(returnData, returnData->length() - realmac->length(), recmac, 0, realmac->length());
733
734                 if (!recmac->equals(realmac))
735                         throw new Error("Local Error: Invalid HMAC!  Potential Attack!");
736
737                 Array<char> *returnData2 = new Array<char>(lengthOfReturnData - recmac->length());
738                 System_arraycopy(returnData, 0, returnData2, 0, returnData2->length());
739
740                 return returnData2;
741         } catch (Exception *e) {
742                 printf("Exception\n");
743         }
744
745         return NULL;
746 }
747
748 void CloudComm::localServerWorkerFunction() {
749         int inputSocket = -1;
750
751         try {
752                 // Local server socket
753                 inputSocket = createSocket(listeningPort);
754         } catch (Exception *e) {
755                 throw new Error("Local server setup failure...");
756         }
757
758         while (!doEnd) {
759                 try {
760                         // Accept incoming socket
761                         int socket = acceptSocket(inputSocket);
762
763                         // Get the encrypted data from the server
764                         int dataSize = readSocketInt(socket);
765                         Array<char> *readData = new Array<char>(dataSize);
766                         readSocketData(socket, readData);
767                         timer->endTime();
768
769                         // Decrypt the data
770                         readData = stripIVAndDecryptSlot(readData);
771                         mac->update(readData, 0, readData->length() - CloudComm_HMAC_SIZE);
772                         Array<char> *genmac = mac->doFinal();
773                         Array<char> *recmac = new Array<char>(CloudComm_HMAC_SIZE);
774                         System_arraycopy(readData, readData->length() - recmac->length(), recmac, 0, recmac->length());
775
776                         if (!recmac->equals(genmac))
777                                 throw new Error("Local Error: Invalid HMAC!  Potential Attack!");
778
779                         Array<char> *returnData = new Array<char>(readData->length() - recmac->length());
780                         System_arraycopy(readData, 0, returnData, 0, returnData->length());
781
782                         // Process the data
783                         Array<char> *sendData = table->acceptDataFromLocal(returnData);
784                         mac->update(sendData, 0, sendData->length());
785                         Array<char> *realmac = mac->doFinal();
786                         Array<char> *totalData = new Array<char>(sendData->length() + realmac->length());
787                         System_arraycopy(sendData, 0, totalData, 0, sendData->length());
788                         System_arraycopy(realmac, 0, totalData, sendData->length(), realmac->length());
789
790                         // Encrypt the data for sending
791                         Array<char> *iv = createIV(table->getMachineId(), table->getLocalSequenceNumber());
792                         Array<char> *encryptedData = encryptSlotAndPrependIV(totalData, iv);
793
794                         timer->startTime();
795                         // Send data to output (length of data, the data)
796                         writeSocketInt(socket, encryptedData->length());
797                         writeSocketData(socket, encryptedData);
798                         close(socket);
799                 } catch (Exception *e) {
800                 }
801         }
802
803         if (inputSocket != -1) {
804                 try {
805                         close(inputSocket);
806                 } catch (Exception *e) {
807                         throw new Error("Local server close failure...");
808                 }
809         }
810 }
811
812 void CloudComm::closeCloud() {
813         doEnd = true;
814
815         if (listeningPort > 0) {
816                 if (pthread_join(localServerThread, NULL) != 0)
817                         throw new Error("Local Server thread join issue...");
818         }
819 }