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