Download | Plain Text | No Line Numbers


  1. /*
  2.  * Copyright (c) 2010, Manuel Mausz. All rights reserved.
  3.  *
  4.  * Redistribution and use in source and binary forms, with or without
  5.  * modification, are permitted provided that the following conditions
  6.  * are met:
  7.  *
  8.  * - Redistributions of source code must retain the above copyright
  9.  * notice, this list of conditions and the following disclaimer.
  10.  *
  11.  * - Redistributions in binary form must reproduce the above copyright
  12.  * notice, this list of conditions and the following disclaimer in the
  13.  * documentation and/or other materials provided with the distribution.
  14.  *
  15.  * - The names of the authors may not be used to endorse or promote products
  16.  * derived from this software without specific prior written permission.
  17.  *
  18.  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
  19.  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  20.  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  21.  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  22.  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  23.  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  24.  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  25.  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  26.  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  27.  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  28.  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  29.  */
  30.  
  31. import static java.lang.System.err;
  32. import static java.lang.System.out;
  33.  
  34. import java.util.Arrays;
  35. import java.util.MissingResourceException;
  36.  
  37. import javax.crypto.*;
  38. import java.security.*;
  39. import org.bouncycastle.openssl.PEMReader;
  40. import org.bouncycastle.util.encoders.Base64;
  41. import org.bouncycastle.openssl.PasswordFinder;
  42.  
  43. import java.net.*;
  44. import java.io.*;
  45.  
  46. /*
  47.  * Client implementation for Lab#1 of DSLab WS10
  48.  * See angabe.pdf for details
  49.  *
  50.  * This code is not documented at all. This is volitional
  51.  *
  52.  * @author Manuel Mausz (0728348)
  53.  */
  54. public class Client
  55. {
  56. public class ProxyConnection
  57. extends CommandNetwork
  58. implements Runnable
  59. {
  60. private final Utils.EncObjectInputStream oin;
  61. private final Utils.EncObjectOutputStream oout;
  62. private final String sharedFolder;
  63. private final Object mainLock;
  64. private final Object intLock;
  65.  
  66. ProxyConnection(Utils.EncObjectInputStream oin, Utils.EncObjectOutputStream oout,
  67. String sharedFolder, Object mainLock, Object intLock)
  68. throws NoSuchMethodException
  69. {
  70. this.oin = oin;
  71. this.oout = oout;
  72. this.sharedFolder = sharedFolder;
  73. this.mainLock = mainLock;
  74. this.intLock = intLock;
  75.  
  76. cmdHandler.register("!error", this, "cmdError");
  77. cmdHandler.register("!output", this, "cmdOutput");
  78. cmdHandler.register("!download", this, "cmdDownload");
  79. cmdHandler.register("!upload", this, "cmdUpload");
  80. cmdHandler.register("!ok", this, "cmdOk");
  81. cmdHandler.register("unknown", this, "cmdUnknown");
  82. }
  83.  
  84. /*------------------------------------------------------------------------*/
  85.  
  86. public void notifyInteractive()
  87. {
  88. synchronized(intLock)
  89. {
  90. intLock.notify();
  91. }
  92. }
  93.  
  94. /*------------------------------------------------------------------------*/
  95.  
  96. public void cmdPrintOutput(PrintStream out, String cmd, String[] args)
  97. throws IOException
  98. {
  99. long num;
  100. if ((num = Utils.parseHeaderNum(args, 0)) < 0)
  101. return;
  102.  
  103. String msg;
  104. for (; num > 0 && (msg = oin.readLine()) != null; --num)
  105. out.println(msg.substring(1));
  106. notifyInteractive();
  107. }
  108.  
  109. /*------------------------------------------------------------------------*/
  110.  
  111. public void cmdError(String cmd, String[] args)
  112. throws IOException
  113. {
  114. cmdPrintOutput(err, cmd, args);
  115. }
  116.  
  117. /*------------------------------------------------------------------------*/
  118.  
  119. public void cmdOutput(String cmd, String[] args)
  120. throws IOException
  121. {
  122. cmdPrintOutput(out, cmd, args);
  123. }
  124.  
  125. /*------------------------------------------------------------------------*/
  126.  
  127. public void cmdDownload(String cmd, String[] args)
  128. {
  129. if (args.length < 2 || args[1].length() <= 0)
  130. {
  131. err.println("Error: Invalid " + cmd + "-command paket from proxy. Ignoring...");
  132. notifyInteractive();
  133. return;
  134. }
  135.  
  136. long filesize;
  137. if ((filesize = Utils.parseHeaderNum(args, 1)) < 0)
  138. return;
  139.  
  140. File file = new File(sharedFolder, args[0]);
  141. file.delete();
  142. try
  143. {
  144. FileOutputStream fout = null;
  145. try
  146. {
  147. fout = new FileOutputStream(file);
  148. }
  149. catch(FileNotFoundException e)
  150. {
  151. err.println("Error: Unable to write to file '" + file + "': " + e.getMessage());
  152. }
  153.  
  154. byte[] buffer = new byte[8 * 1024];
  155. int toread = buffer.length;
  156. while(filesize > 0)
  157. {
  158. if (filesize < toread)
  159. toread = (int) filesize;
  160. int count = oin.read(buffer, 0, toread);
  161. if (count == -1)
  162. throw new IOException("Connection reset by peer");
  163.  
  164. if (fout != null)
  165. {
  166. /* decode that chunk */
  167. byte[] decbuffer = new byte[aesdecrypt.getOutputSize(count)];
  168. int deccount = aesdecrypt.update(buffer, 0, count, decbuffer);
  169. fout.write(decbuffer, 0, deccount);
  170. }
  171. filesize -= count;
  172. }
  173. if (fout != null)
  174. {
  175. /* decryption must be finalized */
  176. byte[] decbuffer = aesdecrypt.doFinal();
  177. fout.write(decbuffer);
  178. }
  179. }
  180. catch(IOException e)
  181. {
  182. err.println("Error: Error during file transfer: " + e.getMessage());
  183. }
  184. catch(GeneralSecurityException e)
  185. {
  186. err.println("Error: Error during decrypting file transfer: " + e.getMessage());
  187. }
  188.  
  189. notifyInteractive();
  190. }
  191.  
  192. /*------------------------------------------------------------------------*/
  193.  
  194. public void cmdUpload(String cmd, String[] args)
  195. {
  196. if (args.length < 1 || args[0].length() <= 0)
  197. {
  198. err.println("Error: Invalid " + cmd + "-command paket from proxy. Ignoring...");
  199. notifyInteractive();
  200. return;
  201. }
  202.  
  203. File file = new File(sharedFolder, args[0]);
  204. if (!file.exists() || !file.getParent().equals(sharedFolder))
  205. {
  206. err.println("Error: File '" + args[0] + "' does not exist");
  207. notifyInteractive();
  208. return;
  209. }
  210. if (!file.isFile())
  211. {
  212. err.println("Error: File '" + args[0] + "' is not a file");
  213. notifyInteractive();
  214. return;
  215. }
  216. if (!file.canRead())
  217. {
  218. err.println("Error: File '" + args[0] + "' is not readable");
  219. notifyInteractive();
  220. return;
  221. }
  222.  
  223. long filesize = file.length();
  224. try
  225. {
  226. FileInputStream fin = new FileInputStream(file);
  227.  
  228. oout.writeLine("!upload2 " + file.getName() + " " + filesize);
  229.  
  230. byte[] buffer = new byte[8 * 1024];
  231. int toread = buffer.length;
  232. while(filesize > 0)
  233. {
  234. if (filesize < toread)
  235. toread = (int) filesize;
  236. int count = fin.read(buffer, 0, toread);
  237. if (count == -1)
  238. throw new IOException("Error while reading from file");
  239.  
  240. /* encode that chunk */
  241. byte[] encbuffer = new byte[aesencrypt.getOutputSize(count)];
  242. int enccount = aesencrypt.update(buffer, 0, count, encbuffer);
  243.  
  244. oout.write(encbuffer, 0, enccount);
  245. filesize -= count;
  246. }
  247. /* encryption must be finalized */
  248. oout.write(aesencrypt.doFinal());
  249. oout.flush();
  250. }
  251. catch(FileNotFoundException e)
  252. {
  253. err.println("Error: File '" + args[0] + "' is not readable");
  254. notifyInteractive();
  255. return;
  256. }
  257. catch(IOException e)
  258. {
  259. err.println("Error during file transfer: " + e.getMessage());
  260. notifyInteractive();
  261. return;
  262. }
  263. catch(GeneralSecurityException e)
  264. {
  265. err.println("Error during encrypting file transfer: " + e.getMessage() + "");
  266. notifyInteractive();
  267. return;
  268. }
  269. }
  270.  
  271. /*------------------------------------------------------------------------*/
  272.  
  273. public void cmdOk(String cmd, String[] args)
  274. throws IOException
  275. {
  276. if (args.length != 4)
  277. {
  278. err.println("Error: Invalid " + cmd + "-command paket from proxy. Ignoring...");
  279. notifyInteractive();
  280. return;
  281. }
  282.  
  283. if (!args[0].equals(mychallenge))
  284. {
  285. err.println("Error: Received invalid challenge from proxy. Ignoring...");
  286. notifyInteractive();
  287. return;
  288. }
  289.  
  290. String secondMessage = cmd + " " + Utils.join(Arrays.asList(args), " ");
  291. assert secondMessage.matches("!ok [" + B64 + "]{43}= [" + B64 + "]{43}= [" + B64 + "]{43}= [" + B64 + "]{22}==") : "2nd message";
  292.  
  293. String proxychallenge = args[1];
  294. javax.crypto.spec.SecretKeySpec seckey = new javax.crypto.spec.SecretKeySpec(Base64.decode(args[2].getBytes()), "AES");
  295. javax.crypto.spec.IvParameterSpec iv = new javax.crypto.spec.IvParameterSpec(Base64.decode(args[3].getBytes()));
  296.  
  297. try
  298. {
  299. aesencrypt.init(Cipher.ENCRYPT_MODE, seckey, iv);
  300. aesdecrypt.init(Cipher.DECRYPT_MODE, seckey, iv);
  301. }
  302. catch(InvalidKeyException e)
  303. {
  304. err.println("Error: invalid AES key: " + e.getMessage());
  305. notifyInteractive();
  306. return;
  307. }
  308. catch(InvalidAlgorithmParameterException e)
  309. {
  310. err.println("Error: invalid AES parameter: " + e.getMessage());
  311. notifyInteractive();
  312. return;
  313. }
  314.  
  315. oout.setCipher(aesencrypt);
  316. oin.setCipher(aesdecrypt);
  317.  
  318. String thirdMessage = proxychallenge;
  319. assert thirdMessage.matches("[" + B64 + "]{43}=") : "3rd message";
  320. oout.writeLine(thirdMessage);
  321. oout.flush();
  322. loggedin = true;
  323. }
  324.  
  325. /*------------------------------------------------------------------------*/
  326.  
  327. public void cmdUnknown(String cmd, String[] args)
  328. {
  329. err.println("Error: Unknown data from proxy: " + cmd + " "
  330. + Utils.join(Arrays.asList(args), " "));
  331. notifyInteractive();
  332. }
  333.  
  334. /*------------------------------------------------------------------------*/
  335.  
  336. public void run()
  337. {
  338. try
  339. {
  340. run(oin);
  341. }
  342. catch(CommandHandler.Exception e)
  343. {
  344. err.println("Internal Error: " + e.getMessage());
  345. }
  346. catch(IOException e)
  347. {
  348. /* ignore that exception
  349.   * thread will shutdown and unlock the main thread
  350.   * which will shutdown the application
  351.   */
  352. }
  353.  
  354. notifyInteractive();
  355. synchronized(mainLock)
  356. {
  357. mainLock.notify();
  358. }
  359. }
  360. }
  361.  
  362. /*==========================================================================*/
  363.  
  364. public class Interactive
  365. extends CommandInteractive
  366. implements Runnable
  367. {
  368. private final InputStream sin;
  369. private final Utils.EncObjectInputStream oin;
  370. private final Utils.EncObjectOutputStream oout;
  371. private final Object mainLock;
  372. private final Object intLock;
  373.  
  374. Interactive(InputStream sin, Utils.EncObjectInputStream oin,
  375. Utils.EncObjectOutputStream oout, Object mainLock, Object intLock)
  376. throws NoSuchMethodException
  377. {
  378. this.sin = sin;
  379. this.mainLock = mainLock;
  380. this.intLock = intLock;
  381. this.oin = oin;
  382. this.oout = oout;
  383.  
  384. cmdHandler.register("unknown", this, "cmdUnknown");
  385. cmdHandler.register("!login", this, "cmdLogin");
  386. cmdHandler.register("!exit", this, "cmdExit");
  387. }
  388.  
  389. /*------------------------------------------------------------------------*/
  390.  
  391. public void waitForSocket()
  392. {
  393. synchronized(intLock)
  394. {
  395. try
  396. {
  397. intLock.wait(1000);
  398. }
  399. catch(InterruptedException e)
  400. {
  401. /* if we get interrupted -> ignore */
  402. }
  403. }
  404. }
  405.  
  406. /*------------------------------------------------------------------------*/
  407.  
  408. public void cmdUnknown(String cmd, String[] args)
  409. throws IOException
  410. {
  411. if (!loggedin)
  412. {
  413. err.println("Not logged in");
  414. return;
  415. }
  416.  
  417. oout.writeLine(cmd + " " + Utils.join(Arrays.asList(args), " "));
  418. oout.flush();
  419. waitForSocket();
  420. }
  421.  
  422. /*------------------------------------------------------------------------*/
  423.  
  424. public void cmdLogin(String cmd, String[] args)
  425. throws IOException
  426. {
  427. if (args.length != 1)
  428. {
  429. err.println("Invalid Syntax: !login <username>");
  430. return;
  431. }
  432. if (loggedin)
  433. {
  434. err.println("Already logged in");
  435. return;
  436. }
  437.  
  438. /* read users private key */
  439. final String user = args[0];
  440. File pemfile = new File(keysDir, user + ".pem");
  441. if (!pemfile.isFile())
  442. {
  443. err.println("Error: Private keyfile '" + pemfile + "' doesn't exist.");
  444. return;
  445. }
  446. if (!pemfile.canRead())
  447. {
  448. err.println("Error: Private keyfile '" + pemfile + "' is not readable.");
  449. return;
  450. }
  451.  
  452. try
  453. {
  454. PEMReader in = new PEMReader(new FileReader(pemfile), new PasswordFinder()
  455. {
  456. @Override
  457. public char[] getPassword()
  458. {
  459. try
  460. {
  461. /* reads the password from standard input for decrypting the private key */
  462. out.println("Enter pass phrase: ");
  463. return new BufferedReader(new InputStreamReader(sin)).readLine().toCharArray();
  464. }
  465. catch(IOException e)
  466. {
  467. char[] tmp = {};
  468. return tmp;
  469. }
  470. }
  471. });
  472. KeyPair keyPair = (KeyPair) in.readObject();
  473. privateKey = keyPair.getPrivate();
  474. rsadecrypt.init(Cipher.DECRYPT_MODE, privateKey);
  475. oin.setCipher(rsadecrypt);
  476. }
  477. catch(FileNotFoundException e)
  478. {
  479. err.println("Error while reading private key of " + user + ". Unable to read keyfile.");
  480. return;
  481. }
  482. catch(IOException e)
  483. {
  484. err.println("Error while reading private key of " + user + ". Maybe wrong pass phrase.");
  485. return;
  486. }
  487. catch(InvalidKeyException e)
  488. {
  489. err.println("Error: invalid key file: " + e.getMessage());
  490. return;
  491. }
  492.  
  493. /* generates a 32 byte secure random number */
  494. SecureRandom secureRandom = new SecureRandom();
  495. byte[] tmp = new byte[32];
  496. secureRandom.nextBytes(tmp);
  497. mychallenge = new String(Base64.encode(tmp));
  498.  
  499. String firstMessage = cmd + " " + Utils.join(Arrays.asList(args), " ") + " " + mychallenge;
  500. assert firstMessage.matches("!login \\w+ [" + B64 + "]{43}=") : "1st message";
  501.  
  502. oout.writeLine(firstMessage);
  503. oout.flush();
  504. waitForSocket();
  505. }
  506.  
  507. /*------------------------------------------------------------------------*/
  508.  
  509. public void cmdExit(String cmd, String[] args)
  510. {
  511. stop();
  512. }
  513.  
  514. /*------------------------------------------------------------------------*/
  515.  
  516. public void printPrompt()
  517. {
  518. out.print(">: ");
  519. out.flush();
  520. }
  521.  
  522. /*------------------------------------------------------------------------*/
  523.  
  524. public void shutdown()
  525. {
  526. try
  527. {
  528. oout.flush();
  529. }
  530. catch(IOException e)
  531. {}
  532. }
  533.  
  534. /*------------------------------------------------------------------------*/
  535.  
  536. public void run()
  537. {
  538. try
  539. {
  540. run(sin);
  541. }
  542. catch(CommandHandler.Exception e)
  543. {
  544. err.println("Internal Error: " + e.getMessage());
  545. }
  546. catch(IOException e)
  547. {
  548. /* ignore that exception
  549.   * thread will shutdown and unlock the main thread
  550.   * which will shutdown the application
  551.   */
  552. }
  553.  
  554. shutdown();
  555. synchronized(mainLock)
  556. {
  557. mainLock.notify();
  558. }
  559. }
  560. }
  561.  
  562. /*==========================================================================*/
  563.  
  564. private static String sharedFolder;
  565. private static String proxyHost;
  566. private static int proxyTCPPort;
  567. private Socket sock = null;
  568. private InputStream sockin = null;
  569. private OutputStream sockout = null;
  570. private Utils.EncObjectInputStream oin = null;
  571. private Utils.EncObjectOutputStream oout = null;
  572. private Thread tPConnection = null;
  573. private Thread tInteractive = null;
  574. private InputStream stdin = null;
  575. private final Object interactiveLock = new Object();
  576. private final Object mainLock = new Object();
  577.  
  578. private static String keysDir;
  579. private static String proxyKey;
  580. private String mychallenge;
  581. private PrivateKey privateKey = null;
  582. private Cipher rsaencrypt, rsadecrypt;
  583. private Cipher aesencrypt, aesdecrypt;
  584. private volatile boolean loggedin = false;
  585. private final String B64 = "a-zA-Z0-9/+";
  586.  
  587. /*--------------------------------------------------------------------------*/
  588.  
  589. public Client()
  590. {
  591. try
  592. {
  593. rsaencrypt = Cipher.getInstance("RSA/NONE/OAEPWithSHA256AndMGF1Padding");
  594. rsadecrypt = Cipher.getInstance("RSA/NONE/OAEPWithSHA256AndMGF1Padding");
  595. aesencrypt = Cipher.getInstance("AES/CTR/NoPadding");
  596. aesdecrypt = Cipher.getInstance("AES/CTR/NoPadding");
  597. }
  598. catch(NoSuchAlgorithmException e)
  599. {
  600. bailout("Unable to initialize cipher: " + e.getMessage());
  601. }
  602. catch(NoSuchPaddingException e)
  603. {
  604. bailout("Unable to initialize cipher: " + e.getMessage());
  605. }
  606. }
  607.  
  608. /*--------------------------------------------------------------------------*/
  609.  
  610. public static void usage()
  611. throws Utils.Shutdown
  612. {
  613. out.println("Usage: Client sharedFolder\n");
  614. out.println("sharedFolder\t...the directory to put downloaded files or to upload files from");
  615.  
  616. // Java is some piece of crap which doesn't allow me to set exitcode w/o
  617. // using System.exit. Maybe someday Java will be a fully functional
  618. // programming language, but I wouldn't bet my money
  619. //System.exit(1);
  620. throw new Utils.Shutdown("FUCK YOU JAVA");
  621. }
  622.  
  623. /*--------------------------------------------------------------------------*/
  624.  
  625. public void bailout(String error)
  626. throws Utils.Shutdown
  627. {
  628. err.println("Error: " + error);
  629. shutdown();
  630.  
  631. // Java is some piece of crap which doesn't allow me to set exitcode w/o
  632. // using System.exit. Maybe someday Java will be a fully functional
  633. // programming language, but I wouldn't bet my money
  634. //System.exit(2);
  635. throw new Utils.Shutdown("FUCK YOU JAVA");
  636. }
  637.  
  638. /*--------------------------------------------------------------------------*/
  639.  
  640. public void parseArgs(String[] args)
  641. {
  642. if (args.length != 1)
  643. usage();
  644.  
  645. sharedFolder = args[0];
  646. File dldir = new File(sharedFolder);
  647. if (!dldir.isDirectory())
  648. bailout("sharedFolder '" + sharedFolder + "' is not a directory");
  649. if (!dldir.canWrite())
  650. bailout("sharedFolder '" + sharedFolder + "' is not writeable");
  651. }
  652.  
  653. /*--------------------------------------------------------------------------*/
  654.  
  655. public void parseConfig()
  656. {
  657. Config config = null;
  658. try
  659. {
  660. config = new Config("client");
  661. }
  662. catch(MissingResourceException e)
  663. {
  664. bailout("configuration file doesn't exist or isn't readable");
  665. }
  666.  
  667. String directive = null;
  668. try
  669. {
  670. directive = "proxy.host";
  671. proxyHost = config.getString(directive);
  672. if (proxyHost.length() == 0)
  673. bailout("configuration directive '" + directive + "' is empty or invalid");
  674.  
  675. directive = "proxy.tcp.port";
  676. proxyTCPPort = config.getInt(directive);
  677. if (proxyTCPPort <= 0 || proxyTCPPort > 65536)
  678. bailout("configuration directive '" + directive + "' must be a valid port number (1 - 65535)");
  679.  
  680. directive = "proxy.key";
  681. proxyKey = config.getString(directive);
  682. File key = new File(proxyKey);
  683. if (!key.isFile())
  684. bailout("configuration directive '" + directive + "' is not a file");
  685. if (!key.canRead())
  686. bailout("configuration directive '" + directive + "' is not readable");
  687. PEMReader in = new PEMReader(new FileReader(key));
  688. PublicKey publicKey = (PublicKey) in.readObject();
  689. rsaencrypt.init(Cipher.ENCRYPT_MODE, publicKey);
  690.  
  691. directive = "keys.dir";
  692. keysDir = config.getString(directive);
  693. File dir = new File(keysDir);
  694. if (!dir.isDirectory())
  695. bailout("configuration directive '" + directive + "' is not a directory");
  696. if (!dir.canRead())
  697. bailout("configuration directive '" + directive + "' is not readable");
  698. }
  699. catch(FileNotFoundException e)
  700. {
  701. bailout("unable to read file of directive '" + directive + "'");
  702. }
  703. catch(IOException e)
  704. {
  705. bailout("while reading proxy public key");
  706. }
  707. catch(InvalidKeyException e)
  708. {
  709. bailout("invalid key file: " + e.getMessage());
  710. }
  711. catch(MissingResourceException e)
  712. {
  713. bailout("configuration directive '" + directive + "' is not set");
  714. }
  715. catch(NumberFormatException e)
  716. {
  717. bailout("configuration directive '" + directive + "' must be numeric");
  718. }
  719. }
  720.  
  721. /*--------------------------------------------------------------------------*/
  722.  
  723. public void shutdown()
  724. {
  725. try
  726. {
  727. if (sockin != null)
  728. sockin.close();
  729. }
  730. catch(IOException e)
  731. {}
  732.  
  733. try
  734. {
  735. if (sockout != null)
  736. sockout.close();
  737. }
  738. catch(IOException e)
  739. {}
  740.  
  741. try
  742. {
  743. if (sock != null && !sock.isClosed())
  744. sock.close();
  745. }
  746. catch(IOException e)
  747. {}
  748.  
  749. try
  750. {
  751. if (tPConnection != null)
  752. tPConnection.join();
  753. }
  754. catch(InterruptedException e)
  755. {}
  756.  
  757. try
  758. {
  759. if (tInteractive != null)
  760. {
  761. tInteractive.interrupt();
  762. tInteractive.join();
  763. }
  764. }
  765. catch(InterruptedException e)
  766. {}
  767.  
  768. try
  769. {
  770. if (stdin != null)
  771. stdin.close();
  772. }
  773. catch(IOException e)
  774. {}
  775. }
  776.  
  777. /*--------------------------------------------------------------------------*/
  778.  
  779. public void run(String[] args)
  780. {
  781. parseArgs(args);
  782. parseConfig();
  783.  
  784. try
  785. {
  786. out.println("Connecting to " + proxyHost + ":" + proxyTCPPort + "...");
  787. sock = new Socket(proxyHost, proxyTCPPort);
  788. sockin = sock.getInputStream();
  789. sockout = sock.getOutputStream();
  790. out.println("Connected...");
  791. }
  792. catch(UnknownHostException e)
  793. {
  794. bailout("Unable to resolve hostname: " + e.getMessage());
  795. }
  796. catch(IOException e)
  797. {
  798. bailout("Unable to connect to proxy: " + e.getMessage());
  799. }
  800.  
  801. synchronized(mainLock)
  802. {
  803. try
  804. {
  805. oin = new Utils.EncObjectInputStream(new BufferedInputStream(sockin));
  806. oout = new Utils.EncObjectOutputStream(sockout);
  807. oout.setCipher(rsaencrypt);
  808. }
  809. catch(IOException e)
  810. {
  811. bailout("Unable to create object stream: " + e.getMessage());
  812. }
  813.  
  814. try
  815. {
  816. tPConnection = new Thread(new ProxyConnection(oin, oout,
  817. sharedFolder, mainLock, interactiveLock));
  818. tPConnection.start();
  819. }
  820. catch(NoSuchMethodException e)
  821. {
  822. bailout("Unable to setup remote command handler");
  823. }
  824.  
  825. try
  826. {
  827. InputStream stdin = java.nio.channels.Channels.newInputStream(
  828. new FileInputStream(FileDescriptor.in).getChannel());
  829. tInteractive = new Thread(new Interactive(stdin, oin, oout,
  830. mainLock, interactiveLock));
  831. tInteractive.start();
  832. }
  833. catch(NoSuchMethodException e)
  834. {
  835. bailout("Unable to setup interactive command handler");
  836. }
  837.  
  838. out.println("Client startup successful!");
  839. try
  840. {
  841. mainLock.wait();
  842. }
  843. catch(InterruptedException e)
  844. {
  845. /* if we get interrupted -> ignore */
  846. }
  847.  
  848. try
  849. {
  850. /* let the threads shutdown */
  851. Thread.sleep(100);
  852. }
  853. catch(InterruptedException e)
  854. {}
  855. }
  856.  
  857. if (tPConnection != null && !tPConnection.isAlive())
  858. bailout("Connection to proxy closed unexpected. Terminating...");
  859.  
  860. shutdown();
  861. }
  862.  
  863. /*--------------------------------------------------------------------------*/
  864.  
  865. public static void main(String[] args)
  866. {
  867. try
  868. {
  869. Client cli = new Client();
  870. cli.run(args);
  871. }
  872. catch(Utils.Shutdown e)
  873. {}
  874. }
  875. }
  876.