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