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.nio.ByteBuffer;
  35. import java.nio.channels.ServerSocketChannel;
  36. import java.nio.channels.SocketChannel;
  37.  
  38. import java.util.Arrays;
  39. import java.util.HashMap;
  40. import java.util.MissingResourceException;
  41. import java.util.concurrent.Executors;
  42. import java.util.concurrent.TimeUnit;
  43. import java.util.concurrent.ScheduledFuture;
  44. import java.util.concurrent.ExecutorService;
  45. import java.util.concurrent.ScheduledExecutorService;
  46.  
  47. import javax.crypto.Mac;
  48. import java.security.InvalidKeyException;
  49. import java.security.NoSuchAlgorithmException;
  50. import org.bouncycastle.util.encoders.Hex;
  51. import org.bouncycastle.util.encoders.Base64;
  52.  
  53. import java.net.*;
  54. import java.io.*;
  55.  
  56. /*
  57.  * Fileserver implementation for Lab#1 of DSLab WS10
  58.  * See angabe.pdf for details
  59.  *
  60.  * This code is not documented at all. This is volitional
  61.  *
  62.  * @author Manuel Mausz (0728348)
  63.  */
  64. public class Fileserver
  65. {
  66. public class ProxyConnection
  67. extends CommandNetwork
  68. implements Runnable
  69. {
  70. private final SocketChannel sock;
  71. private final String sharedFolder;
  72. private final Utils.EncObjectInputStream oin;
  73. private final Utils.EncObjectOutputStream oout;
  74.  
  75. ProxyConnection(SocketChannel sock, String sharedFolder)
  76. throws NoSuchMethodException, IOException
  77. {
  78. this.sock = sock;
  79. this.oout = new Utils.EncObjectOutputStream(sock.socket().getOutputStream());
  80. this.oin = new Utils.EncObjectInputStream(new BufferedInputStream(sock.socket().getInputStream()));
  81. this.sharedFolder = sharedFolder;
  82. this.oout.setMAC(hmac);
  83. this.oin.setMAC(hmac);
  84.  
  85. setOneCommandMode(true);
  86. cmdHandler.register("!list", this, "cmdList");
  87. cmdHandler.register("!download", this, "cmdDownload");
  88. cmdHandler.register("!upload2", this, "cmdUpload2");
  89. cmdHandler.register("unknown", this, "cmdUnknown");
  90. }
  91.  
  92. /*------------------------------------------------------------------------*/
  93.  
  94. public void cmdList(String cmd, String[] args)
  95. throws IOException
  96. {
  97. if (args.length != 0)
  98. {
  99. err.println("Error: Invalid " + cmd + "-command paket from proxy. Ignoring...");
  100. return;
  101. }
  102.  
  103. oout.writeLine(cmd + " " + filelist.size());
  104. for(java.util.Map.Entry<String, Long> file : filelist.entrySet())
  105. oout.writeLine(file.getKey() + " " + file.getValue().toString());
  106. oout.flush();
  107. }
  108.  
  109. /*------------------------------------------------------------------------*/
  110.  
  111. public void cmdDownload(String cmd, String[] args)
  112. throws IOException
  113. {
  114. if (args.length < 2 || args[1].length() <= 0)
  115. {
  116. err.println("Error: Invalid " + cmd + "-command paket from proxy. Ignoring...");
  117. return;
  118. }
  119.  
  120. long credits;
  121. if ((credits = Utils.parseHeaderNum(args, 1)) < 0)
  122. return;
  123.  
  124. File file = new File(sharedFolder, args[0]);
  125. if (!file.exists() || !file.getParent().equals(sharedFolder))
  126. {
  127. Utils.sendError(oout, "File '" + args[0] + "' does not exist");
  128. return;
  129. }
  130. if (!file.isFile())
  131. {
  132. Utils.sendError(oout, "File '" + args[0] + "' is not a file");
  133. return;
  134. }
  135. if (!file.canRead())
  136. {
  137. Utils.sendError(oout, "File '" + args[0] + "' is not readable");
  138. return;
  139. }
  140.  
  141. long filesize = file.length();
  142. if (credits < filesize)
  143. {
  144. Utils.sendOutput(oout, "You don't have enough credits");
  145. return;
  146. }
  147.  
  148. try
  149. {
  150. FileInputStream fin = new FileInputStream(file);
  151.  
  152. oout.writeLine(cmd + " " + file.getName() + " " + filesize);
  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 = fin.read(buffer, 0, toread);
  161. if (count == -1)
  162. throw new IOException("Error while reading from file");
  163. hmac.update(buffer, 0, count);
  164. oout.write(buffer, 0, count);
  165. filesize -= count;
  166. }
  167. oout.write(hmac.doFinal());
  168. }
  169. catch(FileNotFoundException e)
  170. {
  171. Utils.sendError(oout, "File '" + args[0] + "' is not readable");
  172. }
  173. catch(IOException e)
  174. {
  175. err.println("Error during file transfer: " + e.getMessage());
  176. }
  177. }
  178.  
  179. /*------------------------------------------------------------------------*/
  180.  
  181. public void cmdUpload2(String cmd, String[] args)
  182. throws IOException
  183. {
  184. if (args.length < 3 || args[1].length() <= 0)
  185. {
  186. err.println("Error: Invalid " + cmd + "-command paket from proxy. Ignoring...");
  187. return;
  188. }
  189.  
  190. long filesize;
  191. if ((filesize = Utils.parseHeaderNum(args, 1)) < 0)
  192. return;
  193.  
  194. long version;
  195. if ((version = Utils.parseHeaderNum(args, 2)) < 0)
  196. return;
  197.  
  198. File file = new File(sharedFolder, args[0]);
  199. file.delete();
  200. try
  201. {
  202. FileOutputStream fout = null;
  203. try
  204. {
  205. fout = new FileOutputStream(file);
  206. }
  207. catch(FileNotFoundException e)
  208. {
  209. err.println("Error: Unable to write to file '" + file + "': " + e.getMessage());
  210. }
  211.  
  212. byte[] buffer = new byte[8 * 1024];
  213. int toread = buffer.length;
  214. while(filesize > 0)
  215. {
  216. if (filesize < toread)
  217. toread = (int) filesize;
  218. int count = oin.read(buffer, 0, toread);
  219. if (count == -1)
  220. throw new IOException("Connection reset by peer");
  221. if (fout != null)
  222. {
  223. hmac.update(buffer, 0, count);
  224. fout.write(buffer, 0, count);
  225. }
  226. filesize -= count;
  227. }
  228. byte[] hasht = new byte[hmac.getMacLength()];
  229. oin.readFully(hasht);
  230.  
  231. if (fout != null)
  232. {
  233. byte[] hashc = hmac.doFinal();
  234. //TODO
  235. if (!Arrays.equals(hashc, hasht))
  236. {
  237. err.println("HASH NOT EQUAL: File may be corrupt");
  238. filelist.remove(file.getName());
  239. }
  240. else
  241. filelist.put(file.getName(), version);
  242. }
  243. }
  244. catch(IOException e)
  245. {
  246. err.println("Error: Error during file transfer: " + e.getMessage());
  247. }
  248. }
  249.  
  250. /*------------------------------------------------------------------------*/
  251.  
  252. public void cmdUnknown(String cmd, String[] args)
  253. throws IOException
  254. {
  255. err.println("Error: Unknown data from proxy: " + cmd + " "
  256. + Utils.join(Arrays.asList(args), " "));
  257. Utils.sendError(oout, "Unknown command");
  258. }
  259.  
  260. /*------------------------------------------------------------------------*/
  261.  
  262. public void hashError()
  263. throws IOException
  264. {
  265. oout.writeLine("!hasherr");
  266. }
  267.  
  268. /*------------------------------------------------------------------------*/
  269.  
  270. public void shutdown()
  271. {
  272. try
  273. {
  274. oout.flush();
  275. }
  276. catch(IOException e)
  277. {}
  278.  
  279. try
  280. {
  281. oin.close();
  282. }
  283. catch(IOException e)
  284. {}
  285.  
  286. try
  287. {
  288. oout.close();
  289. }
  290. catch(IOException e)
  291. {}
  292.  
  293. try
  294. {
  295. if (sock.isOpen())
  296. sock.close();
  297. }
  298. catch(IOException e)
  299. {}
  300. }
  301.  
  302. /*------------------------------------------------------------------------*/
  303.  
  304. public void run()
  305. {
  306. try
  307. {
  308. out.println("[" + Thread.currentThread().getId() + "] New connection from tcp:/"
  309. + sock.socket().getInetAddress() + ":" + sock.socket().getPort());
  310. try
  311. {
  312. run(oin);
  313. }
  314. catch(Utils.HashError e)
  315. {
  316. hashError();
  317. }
  318. oout.flush();
  319. }
  320. catch(CommandHandler.Exception e)
  321. {
  322. err.println("Internal Error: " + e.getMessage());
  323. }
  324. catch(IOException e)
  325. {
  326. /* ignore that exception
  327.   * it's usually a closed connection from client so
  328.   * we can't do anything about it anyway
  329.   */
  330. }
  331.  
  332. out.println("[" + Thread.currentThread().getId() + "] Connection closed");
  333. shutdown();
  334. }
  335. }
  336.  
  337. /*==========================================================================*/
  338.  
  339. public class TCPSocketReader
  340. implements Runnable
  341. {
  342. private final ServerSocketChannel sschannel;
  343. private final String sharedFolder;
  344. private final Object mainLock;
  345. private final ExecutorService pool;
  346.  
  347. TCPSocketReader(ServerSocketChannel sschannel, String sharedFolder,
  348. Object mainLock)
  349. {
  350. this.sschannel = sschannel;
  351. this.sharedFolder = sharedFolder;
  352. this.mainLock = mainLock;
  353. this.pool = Executors.newCachedThreadPool();
  354. }
  355.  
  356. /*------------------------------------------------------------------------*/
  357.  
  358. public void run()
  359. {
  360. try
  361. {
  362. while(true)
  363. pool.execute(new ProxyConnection(sschannel.accept(), sharedFolder));
  364. }
  365. catch(NoSuchMethodException e)
  366. {
  367. err.println("Error: Unable to setup remote command handler");
  368. }
  369. catch(IOException e)
  370. {
  371. /* ignore that exception
  372.   * thread will shutdown and unlock the main thread
  373.   * which will shutdown the application
  374.   */
  375. }
  376.  
  377. pool.shutdown();
  378. try
  379. {
  380. if (!pool.awaitTermination(100, TimeUnit.MILLISECONDS))
  381. out.println("Trying to shutdown the proxy connections. This may take up to 15 seconds...");
  382. if (!pool.awaitTermination(5, TimeUnit.SECONDS))
  383. {
  384. pool.shutdownNow();
  385. if (!pool.awaitTermination(5, TimeUnit.SECONDS))
  386. err.println("Error: Proxy connections did not terminate. You may have to kill that appplication.");
  387. }
  388. }
  389. catch(InterruptedException e)
  390. {
  391. pool.shutdownNow();
  392. }
  393.  
  394. synchronized(mainLock)
  395. {
  396. mainLock.notify();
  397. }
  398. }
  399. }
  400.  
  401. /*==========================================================================*/
  402.  
  403. public class Interactive
  404. extends CommandInteractive
  405. implements Runnable
  406. {
  407. private final InputStream sin;
  408. private final Object mainLock;
  409.  
  410. Interactive(InputStream sin, Object mainLock)
  411. throws NoSuchMethodException
  412. {
  413. this.sin = sin;
  414. this.mainLock = mainLock;
  415.  
  416. cmdHandler.register("unknown", this, "cmdUnknown");
  417. cmdHandler.register("!exit", this, "cmdExit");
  418. }
  419.  
  420. /*------------------------------------------------------------------------*/
  421.  
  422. public void cmdUnknown(String cmd, String[] args)
  423. {
  424. err.println("Unknown command: " + cmd + " "
  425. + Utils.join(Arrays.asList(args), " "));
  426. }
  427.  
  428. /*------------------------------------------------------------------------*/
  429.  
  430. public void cmdExit(String cmd, String[] args)
  431. {
  432. stop();
  433. }
  434.  
  435. /*------------------------------------------------------------------------*/
  436.  
  437. public void printPrompt()
  438. {
  439. out.print(">: ");
  440. out.flush();
  441. }
  442.  
  443. /*------------------------------------------------------------------------*/
  444.  
  445. public void run()
  446. {
  447. try
  448. {
  449. run(sin);
  450. }
  451. catch(CommandHandler.Exception e)
  452. {
  453. err.println("Internal Error: " + e.getMessage());
  454. }
  455. catch (IOException e)
  456. {
  457. /* ignore that exception
  458.   * thread will shutdown and unlock the main thread
  459.   * which will shutdown the application
  460.   */
  461. }
  462.  
  463. synchronized(mainLock)
  464. {
  465. mainLock.notify();
  466. }
  467. }
  468. }
  469.  
  470. /*==========================================================================*/
  471.  
  472. public class PingTask
  473. implements Runnable
  474. {
  475. private final DatagramSocket sock;
  476. private final DatagramPacket packet;
  477. private final Object mainLock;
  478.  
  479. PingTask(DatagramSocket sock, DatagramPacket packet, Object mainLock)
  480. {
  481. this.sock = sock;
  482. this.packet = packet;
  483. this.mainLock = mainLock;
  484. }
  485.  
  486. /*------------------------------------------------------------------------*/
  487.  
  488. public void run()
  489. {
  490. try
  491. {
  492. sock.send(packet);
  493. }
  494. catch(IOException e)
  495. {
  496. err.println("Error while sending UDP ping packet: " + e.getMessage()
  497. + ". Terminating...");
  498. synchronized(mainLock)
  499. {
  500. mainLock.notify();
  501. }
  502. }
  503. }
  504. }
  505.  
  506. /*==========================================================================*/
  507.  
  508. private static String sharedFolder;
  509. private static String proxyHost;
  510. private static int tcpPort;
  511. private static int proxyUDPPort;
  512. private static int alivePeriod;
  513. private ScheduledExecutorService scheduler = null;
  514. private ServerSocketChannel sschannel = null;
  515. private DatagramSocket dsock = null;
  516. private Thread tTCPSocketReader = null;
  517. private Thread tInteractive = null;
  518. private InputStream stdin = null;
  519. private final Object mainLock = new Object();
  520. private HashMap<String, Long> filelist;
  521.  
  522. private Mac hmac;
  523. private final String B64 = "a-zA-Z0-9/+";
  524.  
  525. /*--------------------------------------------------------------------------*/
  526.  
  527. public Fileserver()
  528. {
  529. filelist = new HashMap<String, Long>();
  530. }
  531.  
  532. /*--------------------------------------------------------------------------*/
  533.  
  534. public static void usage()
  535. throws Utils.Shutdown
  536. {
  537. out.println("Usage: Fileserver sharedFolder tcpPort\n");
  538. out.println("sharedFolder\t...the directory that contains all the files clients can download or have uploaded");
  539. out.println("tcpPort\t\t...the port to be used for instantiating a ServerSocket");
  540.  
  541. // Java is some piece of crap which doesn't allow me to set exitcode w/o
  542. // using System.exit. Maybe someday Java will be a fully functional
  543. // programming language, but I wouldn't bet my money
  544. //System.exit(1);
  545. throw new Utils.Shutdown("FUCK YOU JAVA");
  546. }
  547.  
  548. /*--------------------------------------------------------------------------*/
  549.  
  550. public void bailout(String error)
  551. throws Utils.Shutdown
  552. {
  553. err.println("Error: " + error);
  554. shutdown();
  555.  
  556. // Java is some piece of crap which doesn't allow me to set exitcode w/o
  557. // using System.exit. Maybe someday Java will be a fully functional
  558. // programming language, but I wouldn't bet my money
  559. //System.exit(2);
  560. throw new Utils.Shutdown("FUCK YOU JAVA");
  561. }
  562.  
  563. /*--------------------------------------------------------------------------*/
  564.  
  565. public void parseArgs(String[] args)
  566. {
  567. if (args.length != 2)
  568. usage();
  569.  
  570. sharedFolder = args[0];
  571. File sharedir = new File(sharedFolder);
  572. if (!sharedir.isDirectory())
  573. bailout("sharedFolder '" + sharedFolder + "' is not a directory");
  574. if (!sharedir.canRead())
  575. bailout("sharedFolder '" + sharedFolder + "' is not readable");
  576.  
  577. try
  578. {
  579. tcpPort = Integer.parseInt(args[1]);
  580. if (tcpPort <= 0 || tcpPort > 65536)
  581. bailout("tcpPort must be a valid port number (1 - 65535)");
  582. }
  583. catch(NumberFormatException e)
  584. {
  585. bailout("tcpPort must be numeric");
  586. }
  587. }
  588.  
  589. /*--------------------------------------------------------------------------*/
  590.  
  591. public void parseConfig()
  592. {
  593. Config config = null;
  594. try
  595. {
  596. config = new Config("fileserver");
  597. }
  598. catch(MissingResourceException e)
  599. {
  600. bailout("configuration file doesn't exist or isn't readable");
  601. }
  602.  
  603. String directive = null;
  604. try
  605. {
  606. directive = "proxy.host";
  607. proxyHost = config.getString(directive);
  608. if (proxyHost.length() == 0)
  609. bailout("configuration directive '" + directive + "' is empty or invalid");
  610.  
  611. directive = "proxy.udp.port";
  612. proxyUDPPort = config.getInt(directive);
  613. if (proxyUDPPort <= 0 || proxyUDPPort > 65536)
  614. bailout("configuration directive '" + directive + "' must be a valid port number (1 - 65535)");
  615.  
  616. directive = "fileserver.alive";
  617. alivePeriod = config.getInt(directive);
  618. if (alivePeriod <= 0)
  619. bailout("configuration directive '" + directive + "' must be a positive number");
  620.  
  621. directive = "hmac.key";
  622. File hmackey = new File(config.getString(directive));
  623. if (!hmackey.isFile())
  624. bailout("configuration directive '" + directive + "' is not a file");
  625. if (!hmackey.canRead())
  626. bailout("configuration directive '" + directive + "' is not readable");
  627.  
  628. byte[] keybytes = new byte[1024];
  629. FileInputStream fis = new FileInputStream(hmackey);
  630. fis.read(keybytes);
  631. fis.close();
  632.  
  633. hmac = Mac.getInstance("HmacSHA256");
  634. hmac.init(new javax.crypto.spec.SecretKeySpec(Hex.decode(keybytes), "HmacSHA256"));
  635. }
  636. catch(MissingResourceException e)
  637. {
  638. bailout("configuration directive '" + directive + "' is not set");
  639. }
  640. catch(NumberFormatException e)
  641. {
  642. bailout("configuration directive '" + directive + "' must be numeric");
  643. }
  644. catch(FileNotFoundException e)
  645. {
  646. bailout("unable to read file of directive '" + directive + "'");
  647. }
  648. catch(NoSuchAlgorithmException e)
  649. {
  650. bailout("Unable to initialize cipher: " + e.getMessage());
  651. }
  652. catch(InvalidKeyException e)
  653. {
  654. bailout("invalid key file: " + e.getMessage());
  655. }
  656. catch(IOException e)
  657. {
  658. bailout("Error while reading file: " + e.getMessage());
  659. }
  660. }
  661.  
  662. /*--------------------------------------------------------------------------*/
  663.  
  664. public void readFiles()
  665. {
  666. File file = new File(sharedFolder);
  667. FilenameFilter filter = new FilenameFilter()
  668. {
  669. public boolean accept(File dir, String name)
  670. {
  671. File file = new File(dir, name);
  672. return (file.isFile() && file.canRead());
  673. }
  674. };
  675. for(String filename : file.list(filter))
  676. {
  677. if (!filelist.containsKey(filename))
  678. filelist.put(filename, Long.valueOf(0));
  679. }
  680. }
  681.  
  682. /*--------------------------------------------------------------------------*/
  683.  
  684. public void shutdown()
  685. {
  686. try
  687. {
  688. if (scheduler != null)
  689. {
  690. scheduler.shutdownNow();
  691. scheduler.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
  692. }
  693. }
  694. catch(InterruptedException e)
  695. {}
  696.  
  697. if (dsock != null)
  698. dsock.close();
  699.  
  700. try
  701. {
  702. if (sschannel != null)
  703. sschannel.close();
  704. }
  705. catch(IOException e)
  706. {}
  707.  
  708. try
  709. {
  710. if (tTCPSocketReader != null)
  711. tTCPSocketReader.join();
  712. }
  713. catch(InterruptedException e)
  714. {}
  715.  
  716. try
  717. {
  718. if (tInteractive != null)
  719. {
  720. tInteractive.interrupt();
  721. tInteractive.join();
  722. }
  723. }
  724. catch(InterruptedException e)
  725. {}
  726.  
  727. try
  728. {
  729. if (stdin != null)
  730. stdin.close();
  731. }
  732. catch(IOException e)
  733. {}
  734. }
  735.  
  736. /*--------------------------------------------------------------------------*/
  737.  
  738. public void run(String[] args)
  739. {
  740. parseArgs(args);
  741. parseConfig();
  742. readFiles();
  743.  
  744. synchronized(mainLock)
  745. {
  746. try
  747. {
  748. dsock = new DatagramSocket();
  749. InetAddress proxyaddr = InetAddress.getByName(proxyHost);
  750. String msg = "!alive " + tcpPort;
  751. DatagramPacket dpacket = new DatagramPacket(msg.getBytes(),
  752. msg.getBytes().length, proxyaddr, proxyUDPPort);
  753. assert new String(dpacket.getData()).matches("!alive 1[0-9]{4}");
  754.  
  755. scheduler = Executors.newScheduledThreadPool(1);
  756. ScheduledFuture<?> pingTimer = scheduler.scheduleAtFixedRate(
  757. new PingTask(dsock, dpacket, mainLock),
  758. 0, alivePeriod, TimeUnit.MILLISECONDS);
  759. }
  760. catch(SocketException e)
  761. {
  762. bailout("Unable to create UDP Socket: " + e.getMessage());
  763. }
  764. catch(UnknownHostException e)
  765. {
  766. bailout("Unable to resolve hostname: " + e.getMessage());
  767. }
  768.  
  769. try
  770. {
  771. sschannel = ServerSocketChannel.open();
  772. sschannel.socket().bind(new InetSocketAddress(tcpPort));
  773. tTCPSocketReader = new Thread(new TCPSocketReader(sschannel,
  774. sharedFolder, mainLock));
  775. tTCPSocketReader.start();
  776. out.println("Listening on tcp:/" + sschannel.socket().getLocalSocketAddress());
  777. }
  778. catch(IOException e)
  779. {
  780. bailout("Unable to create TCP Socket: " + e.getMessage());
  781. }
  782.  
  783. try
  784. {
  785. InputStream stdin = java.nio.channels.Channels.newInputStream(
  786. new FileInputStream(FileDescriptor.in).getChannel());
  787. tInteractive = new Thread(new Interactive(stdin, mainLock));
  788. tInteractive.start();
  789. }
  790. catch(NoSuchMethodException e)
  791. {
  792. bailout("Unable to setup interactive command handler");
  793. }
  794.  
  795. out.println("Fileserver startup successful!");
  796. try
  797. {
  798. mainLock.wait();
  799. }
  800. catch(InterruptedException e)
  801. {
  802. /* if we get interrupted -> ignore */
  803. }
  804.  
  805. try
  806. {
  807. /* let the threads shutdown */
  808. Thread.sleep(100);
  809. }
  810. catch(InterruptedException e)
  811. {}
  812. }
  813.  
  814. if (tTCPSocketReader != null && !tTCPSocketReader.isAlive())
  815. bailout("Listening TCP socket closed unexpected. Terminating...");
  816.  
  817. shutdown();
  818. }
  819.  
  820. /*--------------------------------------------------------------------------*/
  821.  
  822. public static void main(String[] args)
  823. {
  824. try
  825. {
  826. Fileserver fserver = new Fileserver();
  827. fserver.run(args);
  828. }
  829. catch(Utils.Shutdown e)
  830. {}
  831. }
  832. }
  833.