4f51e5cb920f7fb62d62604defe1e892d269ce10
[iotcloud.git] / version2 / src / Control / app / src / main / java / iotcloud / CloudComm.java
1 package iotcloud;
2
3 import java.io.*;
4 import java.net.*;
5 import java.util.Arrays;
6 import javax.crypto.*;
7 import javax.crypto.spec.*;
8 import java.security.SecureRandom;
9 import android.util.*;
10 import java.nio.charset.StandardCharsets;
11 import org.spongycastle.crypto.generators.PKCS5S2ParametersGenerator;
12 import org.spongycastle.crypto.digests.SHA256Digest;
13 import org.spongycastle.crypto.params.KeyParameter;
14 import org.spongycastle.crypto.PBEParametersGenerator;
15 import android.content.*;
16
17 /**
18  * This class provides a communication API to the webserver.  It also
19  * validates the HMACs on the slots and handles encryption.
20  * @author Brian Demsky <bdemsky@uci.edu>
21  * @version 1.0
22  */
23
24
25 class CloudComm {
26         private static final int SALT_SIZE = 8;
27         private static final int TIMEOUT_MILLIS = 2000; // 100
28
29         /** Sets the size for the HMAC. */
30         static final int HMAC_SIZE = 32;
31
32         private String baseurl;
33         private Cipher encryptCipher;
34         private Cipher decryptCipher;
35         private Mac mac;
36         private String password;
37         private SecureRandom random;
38         private byte salt[];
39         private Table table;
40         private int listeningPort = -1;
41         private Thread localServerThread = null;
42         private boolean doEnd = false;
43
44         private TimingSingleton timer = null;
45
46         private Context context;
47
48
49
50
51         /**
52          * Empty Constructor needed for child class.
53          */
54         CloudComm() {
55                 timer = TimingSingleton.getInstance();
56         }
57
58         private void deleteFile(Context context) {
59                 File fd = context.getFileStreamPath("config.txt");
60                 fd.delete();
61         }
62
63
64         private void writeToFile(byte[] data,Context context) {
65                 try {
66 //                      OutputStreamWriter outputStreamWriter = new OutputStreamWriter(context.openFileOutput("config.txt", Context.MODE_PRIVATE));
67 //                      outputStreamWriter.write(data);
68 //                      outputStreamWriter.close();
69
70                         FileOutputStream outputStreamWriter = context.openFileOutput("config.txt", Context.MODE_PRIVATE);
71                         outputStreamWriter.write(data);
72                         outputStreamWriter.close();
73
74                 }
75                 catch (IOException e) {
76                         Log.e("Exception", "File write failed: " + e.toString());
77                 }
78         }
79
80         private byte[] readFromFile(Context context) throws FileNotFoundException {
81
82                 byte[] ret1 = null;
83
84                 try {
85                         InputStream inputStream = context.openFileInput("config.txt");
86
87                         if ( inputStream != null ) {
88
89
90                                 ret1 = new byte[inputStream.available()];
91                                 for(int i = 0; i < ret1.length;i++)
92                                 {
93                                         ret1[i] = (byte)inputStream.read();
94                                 }
95
96
97
98
99 //                              InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
100 //                              BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
101 //                              String receiveString = "";
102 //                              StringBuilder stringBuilder = new StringBuilder();
103
104 //                              while ( (receiveString = bufferedReader.readLine()) != null ) {
105 //                                      stringBuilder.append(receiveString);
106 //                              }
107
108                                 inputStream.close();
109 //                              ret = stringBuilder.toString();
110                         }
111                 }
112                 catch (FileNotFoundException e) {
113                         Log.e("login activity", "File not found: " + e.toString());
114
115                         throw e;
116                 } catch (IOException e) {
117                         Log.e("login activity", "Can not read file: " + e.toString());
118                 }
119
120                 return ret1;
121         }
122
123
124
125         /**
126          * Constructor for actual use. Takes in the url and password.
127          */
128         CloudComm(Table _table,  String _baseurl, String _password, int _listeningPort, Context _context) {
129                 timer = TimingSingleton.getInstance();
130                 this.table = _table;
131                 this.baseurl = _baseurl;
132                 this.password = _password;
133                 this.random = new SecureRandom();
134                 this.listeningPort = _listeningPort;
135                 this.context = _context;
136
137
138                 if (this.listeningPort > 0) {
139                         localServerThread = new Thread(new Runnable() {
140                                 public void run() {
141                                         localServerWorkerFunction();
142                                 }
143                         });
144                         localServerThread.start();
145                 }
146         }
147
148         /**
149          * Generates Key from password.
150          */
151         private SecretKeySpec initKey() {
152                 try {
153
154                         Log.e("Ali:::::", "KEY KEY KEY......");
155
156
157
158                         boolean doCrypt = false;
159
160                         byte[] keySaved = null;
161
162                         try {
163 //                              String file = readFromFile(context);
164                                 byte[] dat = readFromFile(context);//file.getBytes();
165
166                                 boolean saltMatch = true;
167                                 for(int i = 0; i < salt.length; i++)
168                                 {
169
170                                         Log.e("ALIasdasdaS:", " " + ((int) salt[i] & 255) + " " + ((int) dat[i] & 255));
171
172                                         if(dat[i] != salt[i])
173                                         {
174                                                 saltMatch = false;
175 //                                              break;
176                                         }
177                                 }
178
179                                 if(saltMatch )
180                                 {
181                                         keySaved = new byte[dat.length - salt.length];
182                                         for(int i = salt.length; i < dat.length;i++)
183                                         {
184                                                 keySaved[i-salt.length] = dat[i];
185                                         }
186                                 }
187                                 else
188                                 {
189                                         doCrypt = true;
190                                         Log.e("Ali:::::", "Salt No Match......");
191
192                                 }
193
194
195
196
197
198                         }
199                         catch (Exception e)
200                         {
201                                 doCrypt = true;
202                         }
203
204
205
206                         if(doCrypt) {
207                                 Log.e("Ali:::::", "Doing Crypt......");
208                                 PKCS5S2ParametersGenerator generator = new PKCS5S2ParametersGenerator(new SHA256Digest());
209                                 generator.init(PBEParametersGenerator.PKCS5PasswordToUTF8Bytes(password.toCharArray()), salt, 65536);
210                                 KeyParameter key = (KeyParameter) generator.generateDerivedMacParameters(128);
211
212
213 //                      PBEKeySpec keyspec = new PBEKeySpec(password.toCharArray(),
214 //                                                          salt,
215 //                                                          65536,
216 //                                                          128);
217 //                      SecretKey tmpkey = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1").generateSecret(keyspec);
218 //                      SecretKey tmpkey = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256").generateSecret(keyspec);
219
220
221 //                      return new SecretKeySpec(tmpkey.getEncoded(), "AES");
222
223
224                                 byte[] keyDat = key.getKey();
225                                 byte[] saveDat = new byte[salt.length + keyDat.length];
226
227                                 for (int i = 0 ; i < salt.length;i++)
228                                 {
229                                         saveDat[i] = salt[i];
230                                 }
231
232                                 for (int i = 0 ; i < keyDat.length;i++)
233                                 {
234                                         saveDat[i + salt.length] = keyDat[i];
235                                 }
236
237
238                                 deleteFile(context);
239                                 writeToFile(saveDat, context);
240
241                                 return new SecretKeySpec(key.getKey(), "AES");
242                         }
243                         else{
244
245                                 Log.e("Ali:::::", "Using Saved......");
246
247                                 return new SecretKeySpec(keySaved, "AES");
248                         }
249
250
251                 } catch (Exception e) {
252                         StringWriter sw = new StringWriter();
253                         PrintWriter pw = new PrintWriter(sw);
254                         e.printStackTrace(pw);
255                          // stack trace as a string
256
257
258                         throw new Error("Failed generating key.   "  + sw.toString());
259                 }
260         }
261
262         /**
263          * Inits all the security stuff
264          */
265         public void initSecurity() throws ServerException {
266                 // try to get the salt and if one does not exist set one
267                 if (!getSalt()) {
268                         //Set the salt
269                         setSalt();
270                 }
271
272                 initCrypt();
273         }
274
275         /**
276          * Inits the HMAC generator.
277          */
278         private void initCrypt() {
279
280                 if (password == null) {
281                         return;
282                 }
283
284                 try {
285                         SecretKeySpec key = initKey();
286                         password = null; // drop password
287                         mac = Mac.getInstance("HmacSHA256");
288                         mac.init(key);
289                         encryptCipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
290                         encryptCipher.init(Cipher.ENCRYPT_MODE, key);
291                         decryptCipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
292                         decryptCipher.init(Cipher.DECRYPT_MODE, key);
293                 } catch (Exception e) {
294                         e.printStackTrace();
295                         throw new Error("Failed To Initialize Ciphers");
296                 }
297         }
298
299         /*
300          * Builds the URL for the given request.
301          */
302         private URL buildRequest(boolean isput, long sequencenumber, long maxentries) throws IOException {
303                 String reqstring = isput ? "req=putslot" : "req=getslot";
304                 String urlstr = baseurl + "?" + reqstring + "&seq=" + sequencenumber;
305                 if (maxentries != 0)
306                         urlstr += "&max=" + maxentries;
307                 return new URL(urlstr);
308         }
309
310         private void setSalt() throws ServerException {
311
312                 if (salt != null) {
313                         // Salt already sent to server so dont set it again
314                         return;
315                 }
316
317                 try {
318                         byte[] saltTmp = new byte[SALT_SIZE];
319                         random.nextBytes(saltTmp);
320
321                         URL url = new URL(baseurl + "?req=setsalt");
322                         
323                         timer.startTime();
324                         URLConnection con = url.openConnection();
325                         HttpURLConnection http = (HttpURLConnection) con;
326
327                         http.setRequestMethod("POST");
328                         http.setFixedLengthStreamingMode(saltTmp.length);
329                         http.setDoOutput(true);
330                         http.setConnectTimeout(TIMEOUT_MILLIS);
331
332                         
333                         http.connect();
334
335                         OutputStream os = http.getOutputStream();
336                         os.write(saltTmp);
337                         os.flush();
338                         
339                         int responsecode = http.getResponseCode();
340                         if (responsecode != HttpURLConnection.HTTP_OK) {
341                                 // TODO: Remove this print
342                                 System.out.println(responsecode);
343                                 throw new Error("Invalid response");
344                         }
345
346                         timer.endTime();
347
348                         salt = saltTmp;
349                 } catch (Exception e) {
350                         // e.printStackTrace();
351                         timer.endTime();
352                         throw new ServerException("Failed setting salt", ServerException.TypeConnectTimeout);
353                 }
354         }
355
356         private boolean getSalt() throws ServerException {
357                 URL url = null;
358                 URLConnection con = null;
359                 HttpURLConnection http = null;
360
361                 try {
362                         url = new URL(baseurl + "?req=getsalt");
363                 } catch (Exception e) {
364                         // e.printStackTrace();
365                         throw new Error("getSlot failed");
366                 }
367                 try {
368
369                         timer.startTime();
370                         con = url.openConnection();
371                         http = (HttpURLConnection) con;
372                         http.setRequestMethod("POST");
373                         http.setConnectTimeout(TIMEOUT_MILLIS);
374                         http.setReadTimeout(TIMEOUT_MILLIS);
375
376                         
377                         http.connect();
378                         timer.endTime();
379
380
381                 } catch (SocketTimeoutException e) {
382                         timer.endTime();
383                         throw new ServerException("getSalt failed", ServerException.TypeConnectTimeout);
384                 } catch (Exception e) {
385                         // e.printStackTrace();
386                         throw new Error("getSlot failed  " + e.toString());
387                 }
388
389                 try {
390
391                         timer.startTime();
392
393                         int responsecode = http.getResponseCode();
394                         if (responsecode != HttpURLConnection.HTTP_OK) {
395                                 // TODO: Remove this print
396                                 // System.out.println(responsecode);
397                                 throw new Error("Invalid response");
398                         }
399
400 //                      Log.e("Aaaaa", "Code " + responsecode);
401
402
403                         InputStream is = http.getInputStream();
404 //
405 //
406 //                      BufferedReader rd= new BufferedReader(new InputStreamReader(is));
407 //                      int line;
408 //                      StringBuilder sb= new StringBuilder();
409 //                      while ((line = rd.read())!= -1)
410 //                      {
411 //                              sb.append((char)line);
412 //                              Log.e("Aaaaa", "line " + line);
413 //
414 //                      }
415 //
416 //
417 //                      int sdfsdfds = (int)sb.toString().charAt(0);
418 //                      Log.e("Aaaaa", "length " + (int)sb.toString().charAt(0));
419 //                      Log.e("Aaaaa", "Res " + sb.toString().length());
420
421
422 //                      is = new ByteArrayInputStream(sb.toString().getBytes(StandardCharsets.UTF_8));
423
424
425 //                      if (is.available() > 0) {
426 //                      if (sb.toString().length() > 0) {
427                         if(true)
428                         {
429                                 try {
430                                         DataInputStream dis = new DataInputStream(is);
431                                         int salt_length = dis.readInt();
432                                         byte[] tmp = new byte[salt_length];
433 //                              byte [] tmp = new byte[8];
434                                         dis.readFully(tmp);
435                                         salt = tmp;
436
437                                         for (int i = 0; i < 8; i++) {
438                                                 Log.e("ALIasdasdaS:", "asd " + ((int) salt[i] & 255));
439                                         }
440
441
442                                         timer.endTime();
443
444                                         return true;
445                                 }
446                                 catch (Exception e)
447                                 {
448                                         timer.endTime();
449
450                                         Log.e("Aaaaa", "Salt No Data");
451
452                                         return false;
453                                 }
454                         }
455                         else {
456
457
458                                 return false;
459                         }
460                 } catch (SocketTimeoutException e) {
461                         timer.endTime();
462
463                         throw new ServerException("getSalt failed", ServerException.TypeInputTimeout);
464                 } catch (Exception e) {
465
466                         throw new Error("getSlot failed + " + e);
467                 }
468         }
469
470         /*
471          * API for putting a slot into the queue.  Returns null on success.
472          * On failure, the server will send slots with newer sequence
473          * numbers.
474          */
475         public Slot[] putSlot(Slot slot, int max) throws ServerException {
476                 URL url = null;
477                 URLConnection con = null;
478                 HttpURLConnection http = null;
479
480                 try {
481                         if (salt == null) {
482                                 if (!getSalt()) {
483                                         throw new ServerException("putSlot failed", ServerException.TypeSalt);
484                                 }
485                                 initCrypt();
486                         }
487
488                         long sequencenumber = slot.getSequenceNumber();
489                         byte[] bytes = slot.encode(mac);
490                         bytes = encryptCipher.doFinal(bytes);
491
492
493
494
495                         url = buildRequest(true, sequencenumber, max);
496
497                         timer.startTime();
498                         con = url.openConnection();
499                         http = (HttpURLConnection) con;
500
501                         http.setRequestMethod("POST");
502                         http.setFixedLengthStreamingMode(bytes.length);
503                         http.setDoOutput(true);
504                         http.setConnectTimeout(TIMEOUT_MILLIS);
505                         http.setReadTimeout(TIMEOUT_MILLIS);
506                         http.connect();
507
508                         OutputStream os = http.getOutputStream();
509                         os.write(bytes);
510                         os.flush();
511
512                         timer.endTime();
513
514
515                         // System.out.println("Bytes Sent: " + bytes.length);
516                 } catch (ServerException e) {
517                         timer.endTime();
518
519                         throw e;
520                 } catch (SocketTimeoutException e) {
521                         timer.endTime();
522
523                         throw new ServerException("putSlot failed", ServerException.TypeConnectTimeout);
524                 } catch (Exception e) {
525                         // e.printStackTrace();
526                         throw new Error("putSlot failed");
527                 }
528
529
530
531                 try {
532                         timer.startTime();
533                         InputStream is = http.getInputStream();
534                         DataInputStream dis = new DataInputStream(is);
535                         byte[] resptype = new byte[7];
536                         dis.readFully(resptype);
537                         timer.endTime();
538
539                         if (Arrays.equals(resptype, "getslot".getBytes()))
540                         {       
541                                 return processSlots(dis);
542                         }
543                         else if (Arrays.equals(resptype, "putslot".getBytes()))
544                         {
545                                 return null;
546                         }
547                         else
548                                 throw new Error("Bad response to putslot");
549
550                 } catch (SocketTimeoutException e) {
551                                 timer.endTime();
552                         throw new ServerException("putSlot failed", ServerException.TypeInputTimeout);
553                 } catch (Exception e) {
554                         // e.printStackTrace();
555                         throw new Error("putSlot failed");
556                 }
557         }
558
559         /**
560          * Request the server to send all slots with the given
561          * sequencenumber or newer.
562          */
563         public Slot[] getSlots(long sequencenumber) throws ServerException {
564                 URL url = null;
565                 URLConnection con = null;
566                 HttpURLConnection http = null;
567
568                 try {
569                         if (salt == null) {
570                                 if (!getSalt()) {
571                                         throw new ServerException("getSlots failed", ServerException.TypeSalt);
572                                 }
573                                 initCrypt();
574                         }
575
576                         url = buildRequest(false, sequencenumber, 0);
577                         timer.startTime();
578                         con = url.openConnection();
579                         http = (HttpURLConnection) con;
580                         http.setRequestMethod("POST");
581                         http.setConnectTimeout(TIMEOUT_MILLIS);
582                         http.setReadTimeout(TIMEOUT_MILLIS);
583
584                         
585
586                         http.connect();
587                         timer.endTime();
588
589                 } catch (SocketTimeoutException e) {
590                         timer.endTime();
591
592                         throw new ServerException("getSlots failed", ServerException.TypeConnectTimeout);
593                 } catch (ServerException e) {
594                         timer.endTime();
595
596                         throw e;
597                 } catch (Exception e) {
598                         // e.printStackTrace();
599                         throw new Error("getSlots failed   " + e.toString());
600                 }
601
602                 try {
603                         
604                         timer.startTime();
605                         InputStream is = http.getInputStream(); 
606                         DataInputStream dis = new DataInputStream(is);
607                         byte[] resptype = new byte[7];
608                         
609                         dis.readFully(resptype);
610                         timer.endTime();
611
612                         if (!Arrays.equals(resptype, "getslot".getBytes()))
613                                 throw new Error("Bad Response: " + new String(resptype));
614
615                         return processSlots(dis);
616                 } catch (SocketTimeoutException e) {
617                         timer.endTime();
618
619                         throw new ServerException("getSlots failed", ServerException.TypeInputTimeout);
620                 } catch (Exception e) {
621                         // e.printStackTrace();
622                         StringWriter sw = new StringWriter();
623                         PrintWriter pw = new PrintWriter(sw);
624                         e.printStackTrace(pw);
625                         throw new Error("getSlots failed   " + sw.toString());
626                 }
627         }
628
629         /**
630          * Method that actually handles building Slot objects from the
631          * server response.  Shared by both putSlot and getSlots.
632          */
633         private Slot[] processSlots(DataInputStream dis) throws Exception {
634                 int numberofslots = dis.readInt();
635                 int[] sizesofslots = new int[numberofslots];
636
637                 Slot[] slots = new Slot[numberofslots];
638                 for (int i = 0; i < numberofslots; i++)
639                         sizesofslots[i] = dis.readInt();
640
641                 for (int i = 0; i < numberofslots; i++) {
642
643                         byte[] data = new byte[sizesofslots[i]];
644                         dis.readFully(data);
645
646                         data = decryptCipher.doFinal(data);
647
648                         slots[i] = Slot.decode(table, data, mac);
649
650                         Log.e("Ali::::", "Slot Process");
651                 }
652                 dis.close();
653                 return slots;
654         }
655
656         public byte[] sendLocalData(byte[] sendData, String host, int port) {
657
658                 if (salt == null) {
659                         return null;
660                 }
661                 try {
662
663                         System.out.println("Passing Locally");
664
665                         mac.update(sendData);
666                         byte[] genmac = mac.doFinal();
667                         byte[] totalData = new byte[sendData.length + genmac.length];
668                         System.arraycopy(sendData, 0, totalData, 0, sendData.length);
669                         System.arraycopy(genmac, 0, totalData, sendData.length, genmac.length);
670
671                         // Encrypt the data for sending
672                         // byte[] encryptedData = encryptCipher.doFinal(totalData);
673                         byte[] encryptedData = encryptCipher.doFinal(totalData);
674
675                         // Open a TCP socket connection to a local device
676                         Socket socket = new Socket(host, port);
677                         socket.setReuseAddress(true);
678                         DataOutputStream output = new DataOutputStream(socket.getOutputStream());
679                         DataInputStream input = new DataInputStream(socket.getInputStream());
680
681
682                         timer.startTime();
683                         // Send data to output (length of data, the data)
684                         output.writeInt(encryptedData.length);
685                         output.write(encryptedData, 0, encryptedData.length);
686                         output.flush();
687
688                         int lengthOfReturnData = input.readInt();
689                         byte[] returnData = new byte[lengthOfReturnData];
690                         input.readFully(returnData);
691
692                         timer.endTime();
693
694                         returnData = decryptCipher.doFinal(returnData);
695
696                         // We are done with this socket
697                         socket.close();
698
699                         mac.update(returnData, 0, returnData.length - HMAC_SIZE);
700                         byte[] realmac = mac.doFinal();
701                         byte[] recmac = new byte[HMAC_SIZE];
702                         System.arraycopy(returnData, returnData.length - realmac.length, recmac, 0, realmac.length);
703
704                         if (!Arrays.equals(recmac, realmac))
705                                 throw new Error("Local Error: Invalid HMAC!  Potential Attack!");
706
707                         byte[] returnData2 = new byte[lengthOfReturnData - recmac.length];
708                         System.arraycopy(returnData, 0, returnData2, 0, returnData2.length);
709
710                         return returnData2;
711                 } catch (SocketTimeoutException e) {
712
713                 } catch (BadPaddingException e) {
714
715                 } catch (IllegalBlockSizeException e) {
716
717                 } catch (UnknownHostException e) {
718
719                 } catch (IOException e) {
720
721                 }
722
723                 return null;
724         }
725
726         private void localServerWorkerFunction() {
727
728                 ServerSocket inputSocket = null;
729
730                 try {
731                         // Local server socket
732                         inputSocket = new ServerSocket(listeningPort);
733                         inputSocket.setReuseAddress(true);
734                         inputSocket.setSoTimeout(TIMEOUT_MILLIS);
735                 } catch (Exception e) {
736                         e.printStackTrace();
737                         throw new Error("Local server setup failure...");
738                 }
739
740                 while (!doEnd) {
741
742                         try {
743                                 // Accept incoming socket
744                                 Socket socket = inputSocket.accept();
745
746                                 DataInputStream input = new DataInputStream(socket.getInputStream());
747                                 DataOutputStream output = new DataOutputStream(socket.getOutputStream());
748
749                                 // Get the encrypted data from the server
750                                 int dataSize = input.readInt();
751                                 byte[] readData = new byte[dataSize];
752                                 input.readFully(readData);
753
754                                 timer.endTime();
755
756                                 // Decrypt the data
757                                 readData = decryptCipher.doFinal(readData);
758
759                                 mac.update(readData, 0, readData.length - HMAC_SIZE);
760                                 byte[] genmac = mac.doFinal();
761                                 byte[] recmac = new byte[HMAC_SIZE];
762                                 System.arraycopy(readData, readData.length - recmac.length, recmac, 0, recmac.length);
763
764                                 if (!Arrays.equals(recmac, genmac))
765                                         throw new Error("Local Error: Invalid HMAC!  Potential Attack!");
766
767                                 byte[] returnData = new byte[readData.length - recmac.length];
768                                 System.arraycopy(readData, 0, returnData, 0, returnData.length);
769
770                                 // Process the data
771                                 // byte[] sendData = table.acceptDataFromLocal(readData);
772                                 byte[] sendData = table.acceptDataFromLocal(returnData);
773
774                                 mac.update(sendData);
775                                 byte[] realmac = mac.doFinal();
776                                 byte[] totalData = new byte[sendData.length + realmac.length];
777                                 System.arraycopy(sendData, 0, totalData, 0, sendData.length);
778                                 System.arraycopy(realmac, 0, totalData, sendData.length, realmac.length);
779
780                                 // Encrypt the data for sending
781                                 byte[] encryptedData = encryptCipher.doFinal(totalData);
782
783
784                                 timer.startTime();
785                                 // Send data to output (length of data, the data)
786                                 output.writeInt(encryptedData.length);
787                                 output.write(encryptedData, 0, encryptedData.length);
788                                 output.flush();
789
790                                 // close the socket
791                                 socket.close();
792                         } catch (SocketTimeoutException e) {
793
794                         } catch (BadPaddingException e) {
795
796                         } catch (IllegalBlockSizeException e) {
797
798                         } catch (UnknownHostException e) {
799
800                         } catch (IOException e) {
801
802                         }
803                 }
804
805                 if (inputSocket != null) {
806                         try {
807                                 inputSocket.close();
808                         } catch (Exception e) {
809                                 e.printStackTrace();
810                                 throw new Error("Local server close failure...");
811                         }
812                 }
813         }
814
815         public void close() {
816                 doEnd = true;
817
818                 if (localServerThread != null) {
819                         try {
820                                 localServerThread.join();
821                         } catch (Exception e) {
822                                 e.printStackTrace();
823                                 throw new Error("Local Server thread join issue...");
824                         }
825                 }
826
827                 // System.out.println("Done Closing Cloud Comm");
828         }
829
830         protected void finalize() throws Throwable {
831                 try {
832                         close();        // close open files
833                 } finally {
834                         super.finalize();
835                 }
836         }
837
838 }