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